[droid] Do not show any ui if pre-checks are OK
[vuplus_xbmc] / xbmc / LangInfo.cpp
1 /*
2  *      Copyright (C) 2005-2012 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "LangInfo.h"
22 #include "settings/AdvancedSettings.h"
23 #include "settings/GUISettings.h"
24 #include "guilib/LocalizeStrings.h"
25 #include "utils/log.h"
26 #include "utils/XBMCTinyXML.h"
27 #include "utils/LangCodeExpander.h"
28
29 using namespace std;
30
31 #define TEMP_UNIT_STRINGS 20027
32
33 #define SPEED_UNIT_STRINGS 20200
34
35 CLangInfo::CRegion::CRegion(const CRegion& region)
36 {
37   m_strName=region.m_strName;
38   m_forceUnicodeFont=region.m_forceUnicodeFont;
39   m_strGuiCharSet=region.m_strGuiCharSet;
40   m_strSubtitleCharSet=region.m_strSubtitleCharSet;
41   m_strDVDMenuLanguage=region.m_strDVDMenuLanguage;
42   m_strDVDAudioLanguage=region.m_strDVDAudioLanguage;
43   m_strDVDSubtitleLanguage=region.m_strDVDSubtitleLanguage;
44   m_strLangLocaleName = region.m_strLangLocaleName;
45   m_strRegionLocaleName = region.m_strRegionLocaleName;
46
47   m_strDateFormatShort=region.m_strDateFormatShort;
48   m_strDateFormatLong=region.m_strDateFormatLong;
49   m_strTimeFormat=region.m_strTimeFormat;
50   m_strMeridiemSymbols[MERIDIEM_SYMBOL_PM]=region.m_strMeridiemSymbols[MERIDIEM_SYMBOL_PM];
51   m_strMeridiemSymbols[MERIDIEM_SYMBOL_AM]=region.m_strMeridiemSymbols[MERIDIEM_SYMBOL_AM];
52   m_strTimeFormat=region.m_strTimeFormat;
53   m_tempUnit=region.m_tempUnit;
54   m_speedUnit=region.m_speedUnit;
55   m_strTimeZone = region.m_strTimeZone;
56 }
57
58 CLangInfo::CRegion::CRegion()
59 {
60   SetDefaults();
61 }
62
63 CLangInfo::CRegion::~CRegion()
64 {
65
66 }
67
68 void CLangInfo::CRegion::SetDefaults()
69 {
70   m_strName="N/A";
71   m_forceUnicodeFont=false;
72   m_strGuiCharSet="CP1252";
73   m_strSubtitleCharSet="CP1252";
74   m_strDVDMenuLanguage="en";
75   m_strDVDAudioLanguage="en";
76   m_strDVDSubtitleLanguage="en";
77   m_strLangLocaleName = "English";
78
79   m_strDateFormatShort="DD/MM/YYYY";
80   m_strDateFormatLong="DDDD, D MMMM YYYY";
81   m_strTimeFormat="HH:mm:ss";
82   m_tempUnit=TEMP_UNIT_CELSIUS;
83   m_speedUnit=SPEED_UNIT_KMH;
84   m_strTimeZone.clear();
85 }
86
87 void CLangInfo::CRegion::SetTempUnit(const CStdString& strUnit)
88 {
89   if (strUnit.Equals("F"))
90     m_tempUnit=TEMP_UNIT_FAHRENHEIT;
91   else if (strUnit.Equals("K"))
92     m_tempUnit=TEMP_UNIT_KELVIN;
93   else if (strUnit.Equals("C"))
94     m_tempUnit=TEMP_UNIT_CELSIUS;
95   else if (strUnit.Equals("Re"))
96     m_tempUnit=TEMP_UNIT_REAUMUR;
97   else if (strUnit.Equals("Ra"))
98     m_tempUnit=TEMP_UNIT_RANKINE;
99   else if (strUnit.Equals("Ro"))
100     m_tempUnit=TEMP_UNIT_ROMER;
101   else if (strUnit.Equals("De"))
102     m_tempUnit=TEMP_UNIT_DELISLE;
103   else if (strUnit.Equals("N"))
104     m_tempUnit=TEMP_UNIT_NEWTON;
105 }
106
107 void CLangInfo::CRegion::SetSpeedUnit(const CStdString& strUnit)
108 {
109   if (strUnit.Equals("kmh"))
110     m_speedUnit=SPEED_UNIT_KMH;
111   else if (strUnit.Equals("mpmin"))
112     m_speedUnit=SPEED_UNIT_MPMIN;
113   else if (strUnit.Equals("mps"))
114     m_speedUnit=SPEED_UNIT_MPS;
115   else if (strUnit.Equals("fth"))
116     m_speedUnit=SPEED_UNIT_FTH;
117   else if (strUnit.Equals("ftm"))
118     m_speedUnit=SPEED_UNIT_FTMIN;
119   else if (strUnit.Equals("fts"))
120     m_speedUnit=SPEED_UNIT_FTS;
121   else if (strUnit.Equals("mph"))
122     m_speedUnit=SPEED_UNIT_MPH;
123   else if (strUnit.Equals("kts"))
124     m_speedUnit=SPEED_UNIT_KTS;
125   else if (strUnit.Equals("beaufort"))
126     m_speedUnit=SPEED_UNIT_BEAUFORT;
127   else if (strUnit.Equals("inchs"))
128     m_speedUnit=SPEED_UNIT_INCHPS;
129   else if (strUnit.Equals("yards"))
130     m_speedUnit=SPEED_UNIT_YARDPS;
131   else if (strUnit.Equals("fpf"))
132     m_speedUnit=SPEED_UNIT_FPF;
133 }
134
135 void CLangInfo::CRegion::SetTimeZone(const CStdString& strTimeZone)
136 {
137   m_strTimeZone = strTimeZone;
138 }
139
140 // set the locale associated with this region global. This affects string
141 // sorting & transformations
142 void CLangInfo::CRegion::SetGlobalLocale()
143 {
144   CStdString strLocale;
145   if (m_strRegionLocaleName.length() > 0)
146   {
147     strLocale = m_strLangLocaleName + "_" + m_strRegionLocaleName;
148 #ifdef _LINUX
149     strLocale += ".UTF-8";
150 #endif
151   }
152
153   CLog::Log(LOGDEBUG, "trying to set locale to %s", strLocale.c_str());
154
155   // We need to set the locale to only change the collate. Otherwise,
156   // decimal separator is changed depending of the current language
157   // (ie. "," in French or Dutch instead of "."). This breaks atof() and
158   // others similar functions.
159 #if defined(__FreeBSD__)
160   // on FreeBSD libstdc++ is compiled with "generic" locale support
161   if (setlocale(LC_COLLATE, strLocale.c_str()) == NULL
162   || setlocale(LC_CTYPE, strLocale.c_str()) == NULL)
163   {
164     strLocale = "C";
165     setlocale(LC_COLLATE, strLocale.c_str());
166     setlocale(LC_CTYPE, strLocale.c_str());
167   }
168 #else
169   locale current_locale = locale::classic(); // C-Locale
170   try
171   {
172     locale lcl = locale(strLocale);
173     strLocale = lcl.name();
174     current_locale = current_locale.combine< collate<wchar_t> >(lcl);
175     current_locale = current_locale.combine< ctype<wchar_t> >(lcl);
176
177     assert(use_facet< numpunct<char> >(current_locale).decimal_point() == '.');
178
179   } catch(...) {
180     current_locale = locale::classic();
181     strLocale = "C";
182   }
183
184   locale::global(current_locale);
185 #endif
186   CLog::Log(LOGINFO, "global locale set to %s", strLocale.c_str());
187 }
188
189 CLangInfo::CLangInfo()
190 {
191   SetDefaults();
192 }
193
194 CLangInfo::~CLangInfo()
195 {
196 }
197
198 bool CLangInfo::Load(const CStdString& strFileName)
199 {
200   SetDefaults();
201
202   CXBMCTinyXML xmlDoc;
203   if (!xmlDoc.LoadFile(strFileName))
204   {
205     CLog::Log(LOGERROR, "unable to load %s: %s at line %d", strFileName.c_str(), xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
206     return false;
207   }
208
209   TiXmlElement* pRootElement = xmlDoc.RootElement();
210   CStdString strValue = pRootElement->Value();
211   if (strValue != CStdString("language"))
212   {
213     CLog::Log(LOGERROR, "%s Doesn't contain <language>", strFileName.c_str());
214     return false;
215   }
216
217   if (pRootElement->Attribute("locale"))
218     m_defaultRegion.m_strLangLocaleName = pRootElement->Attribute("locale");
219
220 #ifdef _WIN32
221   // Windows need 3 chars isolang code
222   if (m_defaultRegion.m_strLangLocaleName.length() == 2)
223   {
224     if (! g_LangCodeExpander.ConvertTwoToThreeCharCode(m_defaultRegion.m_strLangLocaleName, m_defaultRegion.m_strLangLocaleName, true))
225       m_defaultRegion.m_strLangLocaleName = "";
226   }
227
228   if (!g_LangCodeExpander.ConvertWindowsToGeneralCharCode(m_defaultRegion.m_strLangLocaleName, m_languageCodeGeneral))
229     m_languageCodeGeneral = "";
230 #else
231   if (m_defaultRegion.m_strLangLocaleName.length() != 3)
232   {
233     if (!g_LangCodeExpander.ConvertToThreeCharCode(m_languageCodeGeneral, m_defaultRegion.m_strLangLocaleName))
234       m_languageCodeGeneral = "";
235   }
236   else
237     m_languageCodeGeneral = m_defaultRegion.m_strLangLocaleName;
238 #endif
239
240   const TiXmlNode *pCharSets = pRootElement->FirstChild("charsets");
241   if (pCharSets && !pCharSets->NoChildren())
242   {
243     const TiXmlNode *pGui = pCharSets->FirstChild("gui");
244     if (pGui && !pGui->NoChildren())
245     {
246       CStdString strForceUnicodeFont = ((TiXmlElement*) pGui)->Attribute("unicodefont");
247
248       if (strForceUnicodeFont.Equals("true"))
249         m_defaultRegion.m_forceUnicodeFont=true;
250
251       m_defaultRegion.m_strGuiCharSet=pGui->FirstChild()->Value();
252     }
253
254     const TiXmlNode *pSubtitle = pCharSets->FirstChild("subtitle");
255     if (pSubtitle && !pSubtitle->NoChildren())
256       m_defaultRegion.m_strSubtitleCharSet=pSubtitle->FirstChild()->Value();
257   }
258
259   const TiXmlNode *pDVD = pRootElement->FirstChild("dvd");
260   if (pDVD && !pDVD->NoChildren())
261   {
262     const TiXmlNode *pMenu = pDVD->FirstChild("menu");
263     if (pMenu && !pMenu->NoChildren())
264       m_defaultRegion.m_strDVDMenuLanguage=pMenu->FirstChild()->Value();
265
266     const TiXmlNode *pAudio = pDVD->FirstChild("audio");
267     if (pAudio && !pAudio->NoChildren())
268       m_defaultRegion.m_strDVDAudioLanguage=pAudio->FirstChild()->Value();
269
270     const TiXmlNode *pSubtitle = pDVD->FirstChild("subtitle");
271     if (pSubtitle && !pSubtitle->NoChildren())
272       m_defaultRegion.m_strDVDSubtitleLanguage=pSubtitle->FirstChild()->Value();
273   }
274
275   const TiXmlNode *pRegions = pRootElement->FirstChild("regions");
276   if (pRegions && !pRegions->NoChildren())
277   {
278     const TiXmlElement *pRegion=pRegions->FirstChildElement("region");
279     while (pRegion)
280     {
281       CRegion region(m_defaultRegion);
282       region.m_strName=pRegion->Attribute("name");
283       if (region.m_strName.IsEmpty())
284         region.m_strName="N/A";
285
286       if (pRegion->Attribute("locale"))
287         region.m_strRegionLocaleName = pRegion->Attribute("locale");
288
289 #ifdef _WIN32
290       // Windows need 3 chars regions code
291       if (region.m_strRegionLocaleName.length() == 2)
292       {
293         if (! g_LangCodeExpander.ConvertLinuxToWindowsRegionCodes(region.m_strRegionLocaleName, region.m_strRegionLocaleName))
294           region.m_strRegionLocaleName = "";
295       }
296 #endif
297
298       const TiXmlNode *pDateLong=pRegion->FirstChild("datelong");
299       if (pDateLong && !pDateLong->NoChildren())
300         region.m_strDateFormatLong=pDateLong->FirstChild()->Value();
301
302       const TiXmlNode *pDateShort=pRegion->FirstChild("dateshort");
303       if (pDateShort && !pDateShort->NoChildren())
304         region.m_strDateFormatShort=pDateShort->FirstChild()->Value();
305
306       const TiXmlElement *pTime=pRegion->FirstChildElement("time");
307       if (pTime && !pTime->NoChildren())
308       {
309         region.m_strTimeFormat=pTime->FirstChild()->Value();
310         region.m_strMeridiemSymbols[MERIDIEM_SYMBOL_AM]=pTime->Attribute("symbolAM");
311         region.m_strMeridiemSymbols[MERIDIEM_SYMBOL_PM]=pTime->Attribute("symbolPM");
312       }
313
314       const TiXmlNode *pTempUnit=pRegion->FirstChild("tempunit");
315       if (pTempUnit && !pTempUnit->NoChildren())
316         region.SetTempUnit(pTempUnit->FirstChild()->Value());
317
318       const TiXmlNode *pSpeedUnit=pRegion->FirstChild("speedunit");
319       if (pSpeedUnit && !pSpeedUnit->NoChildren())
320         region.SetSpeedUnit(pSpeedUnit->FirstChild()->Value());
321
322       const TiXmlNode *pTimeZone=pRegion->FirstChild("timezone");
323       if (pTimeZone && !pTimeZone->NoChildren())
324         region.SetTimeZone(pTimeZone->FirstChild()->Value());
325
326       m_regions.insert(PAIR_REGIONS(region.m_strName, region));
327
328       pRegion=pRegion->NextSiblingElement("region");
329     }
330
331     const CStdString& strName=g_guiSettings.GetString("locale.country");
332     SetCurrentRegion(strName);
333   }
334
335   LoadTokens(pRootElement->FirstChild("sorttokens"),g_advancedSettings.m_vecTokens);
336
337   return true;
338 }
339
340 void CLangInfo::LoadTokens(const TiXmlNode* pTokens, vector<CStdString>& vecTokens)
341 {
342   if (pTokens && !pTokens->NoChildren())
343   {
344     const TiXmlElement *pToken = pTokens->FirstChildElement("token");
345     while (pToken)
346     {
347       CStdString strSep= " ._";
348       if (pToken->Attribute("separators"))
349         strSep = pToken->Attribute("separators");
350       if (pToken->FirstChild() && pToken->FirstChild()->Value())
351       {
352         if (strSep.IsEmpty())
353           vecTokens.push_back(pToken->FirstChild()->Value());
354         else
355           for (unsigned int i=0;i<strSep.size();++i)
356             vecTokens.push_back(CStdString(pToken->FirstChild()->Value())+strSep[i]);
357       }
358       pToken = pToken->NextSiblingElement();
359     }
360   }
361 }
362
363 void CLangInfo::SetDefaults()
364 {
365   m_regions.clear();
366
367   //Reset default region
368   m_defaultRegion.SetDefaults();
369
370   // Set the default region, we may be unable to load langinfo.xml
371   m_currentRegion=&m_defaultRegion;
372   
373   m_languageCodeGeneral = "eng";
374 }
375
376 CStdString CLangInfo::GetGuiCharSet() const
377 {
378   CStdString strCharSet;
379   strCharSet=g_guiSettings.GetString("locale.charset");
380   if (strCharSet=="DEFAULT")
381     strCharSet=m_currentRegion->m_strGuiCharSet;
382
383   return strCharSet;
384 }
385
386 CStdString CLangInfo::GetSubtitleCharSet() const
387 {
388   CStdString strCharSet=g_guiSettings.GetString("subtitles.charset");
389   if (strCharSet=="DEFAULT")
390     strCharSet=m_currentRegion->m_strSubtitleCharSet;
391
392   return strCharSet;
393 }
394
395 // three char language code (not win32 specific)
396 const CStdString& CLangInfo::GetAudioLanguage() const
397 {
398   if (!m_audioLanguage.empty())
399     return m_audioLanguage;
400
401   return m_languageCodeGeneral;
402 }
403
404 void CLangInfo::SetAudioLanguage(const CStdString &language)
405 {
406   if (language.empty() || !g_LangCodeExpander.ConvertToThreeCharCode(m_audioLanguage, language))
407     m_audioLanguage.clear();
408 }
409
410 // three char language code (not win32 specific)
411 const CStdString& CLangInfo::GetSubtitleLanguage() const
412 {
413   if (!m_subtitleLanguage.empty())
414     return m_subtitleLanguage;
415
416   return m_languageCodeGeneral;
417 }
418
419 void CLangInfo::SetSubtitleLanguage(const CStdString &language)
420 {
421   if (language.empty() || !g_LangCodeExpander.ConvertToThreeCharCode(m_subtitleLanguage, language))
422     m_subtitleLanguage.clear();
423 }
424
425 // two character codes as defined in ISO639
426 const CStdString& CLangInfo::GetDVDMenuLanguage() const
427 {
428   return m_currentRegion->m_strDVDMenuLanguage;
429 }
430
431 // two character codes as defined in ISO639
432 const CStdString& CLangInfo::GetDVDAudioLanguage() const
433 {
434   return m_currentRegion->m_strDVDAudioLanguage;
435 }
436
437 // two character codes as defined in ISO639
438 const CStdString& CLangInfo::GetDVDSubtitleLanguage() const
439 {
440   return m_currentRegion->m_strDVDSubtitleLanguage;
441 }
442
443 const CStdString& CLangInfo::GetLanguageLocale() const
444 {
445   return m_currentRegion->m_strLangLocaleName;
446 }
447
448 const CStdString& CLangInfo::GetRegionLocale() const
449 {
450   return m_currentRegion->m_strRegionLocaleName;
451 }
452
453 // Returns the format string for the date of the current language
454 const CStdString& CLangInfo::GetDateFormat(bool bLongDate/*=false*/) const
455 {
456   if (bLongDate)
457     return m_currentRegion->m_strDateFormatLong;
458   else
459     return m_currentRegion->m_strDateFormatShort;
460 }
461
462 // Returns the format string for the time of the current language
463 const CStdString& CLangInfo::GetTimeFormat() const
464 {
465   return m_currentRegion->m_strTimeFormat;
466 }
467
468 const CStdString& CLangInfo::GetTimeZone() const
469 {
470   return m_currentRegion->m_strTimeZone;
471 }
472
473 // Returns the AM/PM symbol of the current language
474 const CStdString& CLangInfo::GetMeridiemSymbol(MERIDIEM_SYMBOL symbol) const
475 {
476   return m_currentRegion->m_strMeridiemSymbols[symbol];
477 }
478
479 // Fills the array with the region names available for this language
480 void CLangInfo::GetRegionNames(CStdStringArray& array)
481 {
482   for (ITMAPREGIONS it=m_regions.begin(); it!=m_regions.end(); ++it)
483   {
484     CStdString strName=it->first;
485     if (strName=="N/A")
486       strName=g_localizeStrings.Get(416);
487     array.push_back(strName);
488   }
489 }
490
491 // Set the current region by its name, names from GetRegionNames() are valid.
492 // If the region is not found the first available region is set.
493 void CLangInfo::SetCurrentRegion(const CStdString& strName)
494 {
495   ITMAPREGIONS it=m_regions.find(strName);
496   if (it!=m_regions.end())
497     m_currentRegion=&it->second;
498   else if (!m_regions.empty())
499     m_currentRegion=&m_regions.begin()->second;
500   else
501     m_currentRegion=&m_defaultRegion;
502
503   m_currentRegion->SetGlobalLocale();
504 }
505
506 // Returns the current region set for this language
507 const CStdString& CLangInfo::GetCurrentRegion() const
508 {
509   return m_currentRegion->m_strName;
510 }
511
512 CLangInfo::TEMP_UNIT CLangInfo::GetTempUnit() const
513 {
514   return m_currentRegion->m_tempUnit;
515 }
516
517 // Returns the temperature unit string for the current language
518 const CStdString& CLangInfo::GetTempUnitString() const
519 {
520   return g_localizeStrings.Get(TEMP_UNIT_STRINGS+m_currentRegion->m_tempUnit);
521 }
522
523 CLangInfo::SPEED_UNIT CLangInfo::GetSpeedUnit() const
524 {
525   return m_currentRegion->m_speedUnit;
526 }
527
528 // Returns the speed unit string for the current language
529 const CStdString& CLangInfo::GetSpeedUnitString() const
530 {
531   return g_localizeStrings.Get(SPEED_UNIT_STRINGS+m_currentRegion->m_speedUnit);
532 }