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