MyGUI  3.2.0
MyGUI_LanguageManager.cpp
Go to the documentation of this file.
1 
6 /*
7  This file is part of MyGUI.
8 
9  MyGUI is free software: you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  MyGUI is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
21 */
22 #include "MyGUI_Precompiled.h"
23 #include "MyGUI_LanguageManager.h"
24 #include "MyGUI_ResourceManager.h"
25 #include "MyGUI_XmlDocument.h"
26 #include "MyGUI_DataManager.h"
27 #include "MyGUI_FactoryManager.h"
28 
29 namespace MyGUI
30 {
31 
32  const std::string XML_TYPE("Language");
33 
34  template <> LanguageManager* Singleton<LanguageManager>::msInstance = nullptr;
35  template <> const char* Singleton<LanguageManager>::mClassTypeName("LanguageManager");
36 
38  mIsInitialise(false)
39  {
40  }
41 
43  {
44  MYGUI_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice");
45  MYGUI_LOG(Info, "* Initialise: " << getClassTypeName());
46 
47  ResourceManager::getInstance().registerLoadXmlDelegate(XML_TYPE) = newDelegate(this, &LanguageManager::_load);
48 
49  MYGUI_LOG(Info, getClassTypeName() << " successfully initialized");
50  mIsInitialise = true;
51  }
52 
54  {
55  MYGUI_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised");
56  MYGUI_LOG(Info, "* Shutdown: " << getClassTypeName());
57 
58  ResourceManager::getInstance().unregisterLoadXmlDelegate(XML_TYPE);
59 
60  MYGUI_LOG(Info, getClassTypeName() << " successfully shutdown");
61  mIsInitialise = false;
62  }
63 
64  void LanguageManager::_load(xml::ElementPtr _node, const std::string& _file, Version _version)
65  {
66  std::string default_lang;
67  bool event_change = false;
68 
69  // берем детей и крутимся, основной цикл
71  while (root.next(XML_TYPE))
72  {
73  // парсим атрибуты
74  root->findAttribute("default", default_lang);
75 
76  // берем детей и крутимся
78  while (info.next("Info"))
79  {
80  // парсим атрибуты
81  std::string name(info->findAttribute("name"));
82 
83  // доюавляем в карту пользователя
84  if (name.empty())
85  {
86  xml::ElementEnumerator source_info = info->getElementEnumerator();
87  while (source_info.next("Source"))
88  {
89  loadLanguage(source_info->getContent(), true);
90  }
91  }
92  // добавляем в карту языков
93  else
94  {
95  xml::ElementEnumerator source_info = info->getElementEnumerator();
96  while (source_info.next("Source"))
97  {
98  std::string file_source = source_info->getContent();
99  // добавляем в карту
100  mMapFile[name].push_back(file_source);
101 
102  // если добавляемый файл для текущего языка, то подгружаем и оповещаем
103  if (name == mCurrentLanguageName)
104  {
105  loadLanguage(file_source, false);
106  event_change = true;
107  }
108  }
109  }
110 
111  }
112  }
113 
114  if (!default_lang.empty())
115  setCurrentLanguage(default_lang);
116  else if (event_change)
117  eventChangeLanguage(mCurrentLanguageName);
118  }
119 
120  void LanguageManager::setCurrentLanguage(const std::string& _name)
121  {
122  MapListString::iterator item = mMapFile.find(_name);
123  if (item == mMapFile.end())
124  {
125  MYGUI_LOG(Error, "Language '" << _name << "' is not found");
126  return;
127  }
128 
129  mMapLanguage.clear();
130  mCurrentLanguageName = _name;
131 
132  for (VectorString::const_iterator iter = item->second.begin(); iter != item->second.end(); ++iter)
133  {
134  loadLanguage(*iter, false);
135  }
136 
137  eventChangeLanguage(mCurrentLanguageName);
138  }
139 
140  bool LanguageManager::loadLanguage(const std::string& _file, bool _user)
141  {
142  DataStreamHolder data = DataManager::getInstance().getData(_file);
143  if (data.getData() == nullptr)
144  {
145  MYGUI_LOG(Error, "file '" << _file << "' not found");
146  return false;
147  }
148 
149  if (_file.find(".xml") != std::string::npos)
150  _loadLanguageXML(data.getData(), _user);
151  else
152  _loadLanguage(data.getData(), _user);
153 
154  return true;
155  }
156 
157  void LanguageManager::_loadLanguageXML(IDataStream* _stream, bool _user)
158  {
159  xml::Document doc;
160  // формат xml
161  if (doc.open(_stream))
162  {
163  xml::ElementPtr root = doc.getRoot();
164  if (root)
165  {
166  xml::ElementEnumerator tag = root->getElementEnumerator();
167  while (tag.next("Tag"))
168  {
169  if (_user)
170  mUserMapLanguage[tag->findAttribute("name")] = tag->getContent();
171  else
172  mMapLanguage[tag->findAttribute("name")] = tag->getContent();
173  }
174  }
175  }
176  }
177 
178  void LanguageManager::_loadLanguage(IDataStream* _stream, bool _user)
179  {
180  // формат txt
181  std::string read;
182  while (!_stream->eof())
183  {
184  _stream->readline(read, '\n');
185  if (read.empty()) continue;
186 
187  // заголовок утф
188  if ((uint8)read[0] == 0xEF && read.size() > 2)
189  {
190  read.erase(0, 3);
191  }
192 
193  if (read[read.size() - 1] == '\r') read.erase(read.size() - 1, 1);
194  if (read.empty()) continue;
195 
196  size_t pos = read.find_first_of(" \t");
197  if (_user)
198  {
199  if (pos == std::string::npos) mUserMapLanguage[read] = "";
200  else mUserMapLanguage[read.substr(0, pos)] = read.substr(pos + 1, std::string::npos);
201  }
202  else
203  {
204  if (pos == std::string::npos) mMapLanguage[read] = "";
205  else mMapLanguage[read.substr(0, pos)] = read.substr(pos + 1, std::string::npos);
206  }
207  }
208  }
209 
211  {
212  UString result(_line);
213 
214  bool replace = false;
215  do
216  {
217  result = replaceTagsPass(result, replace);
218  }
219  while (replace);
220 
221  return result;
222  }
223 
225  {
226  MapLanguageString::iterator iter = mMapLanguage.find(_tag);
227  if (iter != mMapLanguage.end())
228  {
229  return iter->second;
230  }
231 
232  MapLanguageString::iterator iterUser = mUserMapLanguage.find(_tag);
233  if (iterUser != mUserMapLanguage.end())
234  {
235  return iterUser->second;
236  }
237 
238  return _tag;
239  }
240 
241  const std::string& LanguageManager::getCurrentLanguage() const
242  {
243  return mCurrentLanguageName;
244  }
245 
246  void LanguageManager::addUserTag(const UString& _tag, const UString& _replace)
247  {
248  mUserMapLanguage[_tag] = _replace;
249  }
250 
252  {
253  mUserMapLanguage.clear();
254  }
255 
256  bool LanguageManager::loadUserTags(const std::string& _file)
257  {
258  return loadLanguage(_file, true);
259  }
260 
261  UString LanguageManager::replaceTagsPass(const UString& _line, bool& _replaceResult)
262  {
263  _replaceResult = false;
264 
265  // вот хз, что быстрее, итераторы или математика указателей,
266  // для непонятно какого размера одного символа UTF8
267  UString line(_line);
268 
269  UString::iterator end = line.end();
270  for (UString::iterator iter = line.begin(); iter != end; )
271  {
272  if (*iter == '#')
273  {
274  ++iter;
275  if (iter == end)
276  {
277  return line;
278  }
279  else
280  {
281  if (*iter != '{')
282  {
283  ++iter;
284  continue;
285  }
286  UString::iterator iter2 = iter;
287  ++iter2;
288 
289  while (true)
290  {
291  if (iter2 == end)
292  return line;
293 
294  if (*iter2 == '}')
295  {
296  size_t start = iter - line.begin();
297  size_t len = (iter2 - line.begin()) - start - 1;
298  const UString& tag = line.substr(start + 1, len);
299  UString replacement;
300 
301  bool find = true;
302  // try to find in loaded from resources language strings
303  MapLanguageString::iterator replace = mMapLanguage.find(tag);
304  if (replace != mMapLanguage.end())
305  {
306  replacement = replace->second;
307  }
308  else
309  {
310  // try to find in user language strings
311  replace = mUserMapLanguage.find(tag);
312  if (replace != mUserMapLanguage.end())
313  {
314  replacement = replace->second;
315  }
316  else
317  {
318  find = false;
319  }
320  }
321 
322  // try to ask user if event assigned or use #{_tag} instead
323  if (!find)
324  {
325  if (!eventRequestTag.empty())
326  {
327  eventRequestTag(tag, replacement);
328  }
329  else
330  {
331  iter = line.insert(iter, '#') + size_t(len + 2);
332  end = line.end();
333  break;
334  }
335  }
336 
337  _replaceResult = true;
338 
339  iter = line.erase(iter - size_t(1), iter2 + size_t(1));
340  size_t pos = iter - line.begin();
341  line.insert(pos, replacement);
342  iter = line.begin() + pos + replacement.length();
343  end = line.end();
344  if (iter == end)
345  return line;
346  break;
347  }
348  ++iter2;
349  }
350  }
351  }
352  else
353  {
354  ++iter;
355  }
356  }
357 
358  return line;
359  }
360 
361 } // namespace MyGUI