]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/intl.cpp
added init.cpp
[wxWidgets.git] / src / common / intl.cpp
index 1176aa6ab2c1d3c0273939cd3e9f156c3800dc69..684c9a5f2516b0e2418017183a1642a6c51f2eb0 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     29/01/98
 // RCS-ID:      $Id$
 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // ============================================================================
@@ -147,7 +147,7 @@ static inline wxString ExtractNotLang(const wxString& langFull)
 // This is a "low-level" class and is used only by wxMsgCatalog
 // ----------------------------------------------------------------------------
 
-WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash)
+WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash);
 
 class wxMsgCatalogFile
 {
@@ -202,6 +202,8 @@ private:
     inline size_t32 Swap(size_t32 ui) const;
 
     bool          m_bSwapped;   // wrong endianness?
+
+    DECLARE_NO_COPY_CLASS(wxMsgCatalogFile)
 };
 
 
@@ -300,6 +302,15 @@ static wxString GetFullSearchPath(const wxChar *lang)
     if ( pszLcPath != NULL )
         searchPath << GetAllMsgCatalogSubdirs(pszLcPath, lang);
 
+#ifdef __UNIX__
+    // add some standard ones and the one in the tree where wxWin was installed:
+    searchPath
+        << GetAllMsgCatalogSubdirs(wxString(wxGetInstallPrefix()) + wxT("/share/locale"), lang)
+        << GetAllMsgCatalogSubdirs(wxT("/usr/share/locale"), lang)
+        << GetAllMsgCatalogSubdirs(wxT("/usr/lib/locale"), lang)
+        << GetAllMsgCatalogSubdirs(wxT("/usr/local/share/locale"), lang);
+#endif // __UNIX__
+
     // then take the current directory
     // FIXME it should be the directory of the executable
 #ifdef __WXMAC__
@@ -310,15 +321,6 @@ static wxString GetFullSearchPath(const wxChar *lang)
 #else // !Mac
     searchPath << GetAllMsgCatalogSubdirs(wxT("."), lang);
 
-#ifdef __UNIX__
-    // and finally add some standard ones
-    searchPath
-        << GetAllMsgCatalogSubdirs(wxString(wxGetInstallPrefix()) + wxT("/share/locale"), lang)
-        << GetAllMsgCatalogSubdirs(wxT("/usr/share/locale"), lang)
-        << GetAllMsgCatalogSubdirs(wxT("/usr/lib/locale"), lang)
-        << GetAllMsgCatalogSubdirs(wxT("/usr/local/share/locale"), lang);
-#endif // __UNIX__
-
 #endif // platform
 
     return searchPath;
@@ -506,7 +508,7 @@ wxString wxMsgCatalogFile::GetCharset() const
         return wxEmptyString;
     }
 
-    wxString header(StringAtOfs(m_pTransTable, 0));
+    wxString header = wxString::FromAscii( StringAtOfs(m_pTransTable, 0));
     wxString charset;
     int pos = header.Find(wxT("Content-Type: text/plain; charset="));
     if ( pos == wxNOT_FOUND )
@@ -609,8 +611,11 @@ bool wxLocale::Init(const wxChar *szName,
   {
     // the argument to setlocale()
     szLocale = szShort;
+
+    wxCHECK_MSG( szLocale, FALSE, _T("no locale to set in wxLocale::Init()") );
   }
-  m_pszOldLocale = wxSetlocale(LC_ALL, szLocale);
+
+  m_pszOldLocale = wxStrdup(wxSetlocale(LC_ALL, szLocale));
   if ( m_pszOldLocale == NULL )
     wxLogError(_("locale '%s' can not be set."), szLocale);
 
@@ -641,11 +646,7 @@ bool wxLocale::Init(const wxChar *szName,
 
 bool wxLocale::Init(int language, int flags)
 {
-    wxLanguageInfo *info = NULL;
     int lang = language;
-
-    CreateLanguagesDB();
-
     if (lang == wxLANGUAGE_DEFAULT)
     {
         // auto detect the language
@@ -658,17 +659,7 @@ bool wxLocale::Init(int language, int flags)
        return FALSE;
     }
 
-    if (lang != wxLANGUAGE_DEFAULT)
-    {
-        for (size_t i = 0; i < ms_languagesDB->GetCount(); i++)
-        {
-            if (ms_languagesDB->Item(i).Language == lang)
-            {
-                info = &ms_languagesDB->Item(i);
-                break;
-            }
-        }
-    }
+    const wxLanguageInfo *info = GetLanguageInfo(lang);
 
     // Unknown language:
     if (info == NULL)
@@ -680,7 +671,6 @@ bool wxLocale::Init(int language, int flags)
     wxString name = info->Description;
     wxString canonical = info->CanonicalName;
     wxString locale;
-    const wxChar *retloc;
 
     // Set the locale:
 #if defined(__UNIX__) && !defined(__WXMAC__)
@@ -689,90 +679,142 @@ bool wxLocale::Init(int language, int flags)
     else
         locale = info->CanonicalName;
 
-    retloc = wxSetlocale(LC_ALL, locale);
+    wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale);
 
-    if (retloc == NULL)
+    if ( !retloc )
     {
         // Some C libraries don't like xx_YY form and require xx only
         retloc = wxSetlocale(LC_ALL, locale.Mid(0,2));
     }
-    if (retloc == NULL)
+    if ( !retloc )
     {
         // Some C libraries (namely glibc) still use old ISO 639,
         // so will translate the abbrev for them
         wxString mid = locale.Mid(0,2);
-        if (mid == wxT("he")) locale = wxT("iw") + locale.Mid(3);
-        else if (mid == wxT("id")) locale = wxT("in") + locale.Mid(3);
-        else if (mid == wxT("yi")) locale = wxT("ji") + locale.Mid(3);
+        if (mid == wxT("he"))
+            locale = wxT("iw") + locale.Mid(3);
+        else if (mid == wxT("id"))
+            locale = wxT("in") + locale.Mid(3);
+        else if (mid == wxT("yi"))
+            locale = wxT("ji") + locale.Mid(3);
+        else if (mid == wxT("nb"))
+            locale = wxT("no_NO");
+        else if (mid == wxT("nn"))
+            locale = wxT("no_NY");
+
         retloc = wxSetlocale(LC_ALL, locale);
     }
-    if (retloc == NULL)
+    if ( !retloc )
     {
         // (This time, we changed locale in previous if-branch, so try again.)
         // Some C libraries don't like xx_YY form and require xx only
         retloc = wxSetlocale(LC_ALL, locale.Mid(0,2));
     }
-    if (retloc == NULL)
+    if ( !retloc )
     {
         wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str());
         return FALSE;
     }
 #elif defined(__WIN32__)
+
+    #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__))
+        // NB: setlocale() from msvcrt.dll (used by VC++ and Mingw)
+        //     can't set locale to language that can only be written using
+        //     Unicode.  Therefore wxSetlocale call failed, but we don't want
+        //     to report it as an error -- so that at least message catalogs
+        //     can be used. Watch for code marked with
+        //     #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow.
+        #define SETLOCALE_FAILS_ON_UNICODE_LANGS
+    #endif
+    
+    wxMB2WXbuf retloc = wxT("C");
     if (language != wxLANGUAGE_DEFAULT)
     {
         if (info->WinLang == 0)
         {
             wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str());
-            retloc = wxT("C");
+            // retloc already set to "C"
         }
         else
         {
+            int codepage = -1;
             wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang),
                                      SORT_DEFAULT);
-            if (SetThreadLocale(lcid))
-                retloc = wxSetlocale(LC_ALL, wxEmptyString);
+            SetThreadLocale(lcid);
+            // NB: we must translate LCID to CRT's setlocale string ourselves,
+            //     because SetThreadLocale does not modify change the
+            //     interpretation of setlocale(LC_ALL, "") call:
+            wxChar buffer[256];
+            buffer[0] = wxT('\0');
+            GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256);
+            locale << buffer;
+            if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0)
+                locale << wxT("_") << buffer;
+            if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, 256) > 0)
+            {
+                codepage = wxAtoi(buffer);
+                if (codepage != 0)
+                    locale << wxT(".") << buffer;
+            }
+            if (locale.IsEmpty())
+            {
+                wxLogLastError(wxT("SetThreadLocale"));
+                wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
+                return FALSE;
+            }
             else
             {
-                // Windows9X doesn't support SetThreadLocale, so we must
-                // translate LCID to CRT's setlocale string ourselves
-                locale.Empty();
-                if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
-                {
-                    wxChar buffer[256];
-                    buffer[0] = wxT('\0');
-                    GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256);
-                    locale << buffer;
-                    if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0)
-                        locale << wxT("_") << buffer;
-                }
-                if (locale.IsEmpty())
+                retloc = wxSetlocale(LC_ALL, locale);
+#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
+                if (codepage == 0 && (const wxChar*)retloc == NULL)
                 {
-                    wxLogLastError(wxT("SetThreadLocale"));
-                    wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
-                    return FALSE;
+                    retloc = wxT("C");
                 }
-                else
-                    retloc = wxSetlocale(LC_ALL, locale);
+#endif
             }
         }
     }
     else
+    {
         retloc = wxSetlocale(LC_ALL, wxEmptyString);
+#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
+        if ((const wxChar*)retloc == NULL)
+        {
+            wxChar buffer[16];
+            if (GetLocaleInfo(LOCALE_USER_DEFAULT,
+                              LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 &&
+                 wxStrcmp(buffer, wxT("0")) == 0)
+            {
+                retloc = wxT("C");
+            }
+        }
+#endif
+    }
 
-    if (retloc == NULL)
+    if ( !retloc )
     {
         wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
         return FALSE;
     }
-#elif defined(__WXMAC__)
-    retloc = wxSetlocale(LC_ALL , wxEmptyString);
+#elif defined(__WXMAC__) || defined(__WXPM__)
+    wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString);
 #else
     return FALSE;
+    #define WX_NO_LOCALE_SUPPORT
 #endif
 
-    return Init(name, canonical, wxString(retloc),
-                (flags & wxLOCALE_LOAD_DEFAULT) != 0,
-                (flags & wxLOCALE_CONV_ENCODING) != 0);
+#ifndef WX_NO_LOCALE_SUPPORT
+    wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL;
+    bool ret = Init(name, canonical, retloc,
+                    (flags & wxLOCALE_LOAD_DEFAULT) != 0,
+                    (flags & wxLOCALE_CONV_ENCODING) != 0);
+    free(szLocale);
+
+    if ( ret )
+        m_language = lang;
+
+    return ret;
+#endif
 }
 
 
@@ -858,10 +900,16 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix)
         wxString lang;
         if ( langOrig == wxT("iw"))
             lang = _T("he");
-        else if ( langOrig == wxT("in") )
+        else if (langOrig == wxT("in"))
             lang = wxT("id");
-        else if ( langOrig == wxT("ji") )
+        else if (langOrig == wxT("ji"))
             lang = wxT("yi");
+        else if (langOrig == wxT("no_NO"))
+            lang = wxT("nb_NO");
+        else if (langOrig == wxT("no_NY"))
+            lang = wxT("nn_NO");
+        else if (langOrig == wxT("no"))
+            lang = wxT("nb_NO");
         else
             lang = langOrig;
 
@@ -917,279 +965,279 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix)
         }
     }
 #elif defined(__WXMAC__)
-    const char* lc = NULL ;
+    const wxChar * lc = NULL ;
     long lang = GetScriptVariable( smSystemScript, smScriptLang) ;
     switch( GetScriptManagerVariable( smRegionCode ) ) {
       case verUS :
-        lc = "en_US" ;
+        lc = wxT("en_US") ;
         break ;
       case verFrance :
-        lc = "fr_FR" ;
+        lc = wxT("fr_FR") ;
         break ;
       case verBritain :
-        lc = "en_GB" ;
+        lc = wxT("en_GB") ;
         break ;
       case verGermany :
-        lc = "de_DE" ;
+        lc = wxT("de_DE") ;
         break ;
       case verItaly :
-        lc = "it_IT" ;
+        lc = wxT("it_IT") ;
         break ;
       case verNetherlands :
-        lc = "nl_NL" ;
+        lc = wxT("nl_NL") ;
         break ;
       case verFlemish :
-        lc = "nl_BE" ;
+        lc = wxT("nl_BE") ;
         break ;
       case verSweden :
-        lc = "sv_SE" ;
+        lc = wxT("sv_SE" );
         break ;
       case verSpain :
-        lc = "es_ES" ;
+        lc = wxT("es_ES" );
         break ;
       case verDenmark :
-        lc = "da_DK" ;
+        lc = wxT("da_DK") ;
         break ;
       case verPortugal :
-        lc = "pt_PT" ;
+        lc = wxT("pt_PT") ;
         break ;
       case verFrCanada:
-        lc = "fr_CA" ;
+        lc = wxT("fr_CA") ;
         break ;
       case verNorway:
-        lc = "no_NO" ;
+        lc = wxT("nb_NO") ;
         break ;
       case verIsrael:
-        lc = "iw_IL" ;
+        lc = wxT("iw_IL") ;
         break ;
       case verJapan:
-        lc = "ja_JP" ;
+        lc = wxT("ja_JP") ;
         break ;
       case verAustralia:
-        lc = "en_AU" ;
+        lc = wxT("en_AU") ;
         break ;
       case verArabic:
-        lc = "ar" ;
+        lc = wxT("ar") ;
         break ;
       case verFinland:
-        lc = "fi_FI" ;
+        lc = wxT("fi_FI") ;
         break ;
       case verFrSwiss:
-        lc = "fr_CH" ;
+        lc = wxT("fr_CH") ;
         break ;
       case verGrSwiss:
-        lc = "de_CH" ;
+        lc = wxT("de_CH") ;
         break ;
       case verGreece:
-        lc = "el_GR" ;
+        lc = wxT("el_GR") ;
         break ;
       case verIceland:
-        lc = "is_IS" ;
+        lc = wxT("is_IS") ;
         break ;
       case verMalta:
-        lc = "mt_MT" ;
+        lc = wxT("mt_MT") ;
         break ;
       case verCyprus:
       // _CY is not part of wx, so we have to translate according to the system language
         if ( lang == langGreek ) {
-          lc = "el_GR" ;
+          lc = wxT("el_GR") ;
         }
         else if ( lang == langTurkish ) {
-          lc = "tr_TR" ;
+          lc = wxT("tr_TR") ;
         }
         break ;
       case verTurkey:
-        lc = "tr_TR" ;
+        lc = wxT("tr_TR") ;
         break ;
       case verYugoCroatian:
-        lc = "hr_HR" ;
+        lc = wxT("hr_HR") ;
         break ;
       case verIndiaHindi:
-        lc = "hi_IN" ;
+        lc = wxT("hi_IN") ;
         break ;
       case verPakistanUrdu:
-        lc = "ur_PK" ;
+        lc = wxT("ur_PK") ;
         break ;
       case verTurkishModified:
-        lc = "tr_TR" ;
+        lc = wxT("tr_TR") ;
         break ;
       case verItalianSwiss:
-        lc = "it_CH" ;
+        lc = wxT("it_CH") ;
         break ;
       case verInternational:
-        lc = "en" ;
+        lc = wxT("en") ;
         break ;
       case verRomania:
-        lc = "ro_RO" ;
+        lc = wxT("ro_RO") ;
         break ;
       case verGreecePoly:
-        lc = "el_GR" ;
+        lc = wxT("el_GR") ;
         break ;
       case verLithuania:
-        lc = "lt_LT" ;
+        lc = wxT("lt_LT") ;
         break ;
       case verPoland:
-        lc = "pl_PL" ;
+        lc = wxT("pl_PL") ;
         break ;
       case verMagyar :
       case verHungary:
-        lc = "hu_HU" ;
+        lc = wxT("hu_HU") ;
         break ;
       case verEstonia:
-        lc = "et_EE" ;
+        lc = wxT("et_EE") ;
         break ;
       case verLatvia:
-        lc = "lv_LV" ;
+        lc = wxT("lv_LV") ;
         break ;
       case verSami:
         // not known
         break ;
       case verFaroeIsl:
-        lc = "fo_FO" ;
+        lc = wxT("fo_FO") ;
         break ;
       case verIran:
-        lc = "fa_IR" ;
+        lc = wxT("fa_IR") ;
         break ;
       case verRussia:
-        lc = "ru_RU" ;
+        lc = wxT("ru_RU") ;
         break ;
        case verIreland:
-        lc = "ga_IE" ;
+        lc = wxT("ga_IE") ;
         break ;
       case verKorea:
-        lc = "ko_KR" ;
+        lc = wxT("ko_KR") ;
         break ;
       case verChina:
-        lc = "zh_CN" ;
+        lc = wxT("zh_CN") ;
         break ;
       case verTaiwan:
-        lc = "zh_TW" ;
+        lc = wxT("zh_TW") ;
         break ;
       case verThailand:
-        lc = "th_TH" ;
+        lc = wxT("th_TH") ;
         break ;
       case verCzech:
-        lc = "cs_CZ" ;
+        lc = wxT("cs_CZ") ;
         break ;
       case verSlovak:
-        lc = "sk_SK" ;
+        lc = wxT("sk_SK") ;
         break ;
       case verBengali:
-        lc = "bn" ;
+        lc = wxT("bn") ;
         break ;
       case verByeloRussian:
-        lc = "be_BY" ;
+        lc = wxT("be_BY") ;
         break ;
       case verUkraine:
-        lc = "uk_UA" ;
+        lc = wxT("uk_UA") ;
         break ;
       case verGreeceAlt:
-        lc = "el_GR" ;
+        lc = wxT("el_GR") ;
         break ;
       case verSerbian:
-        lc = "sr_YU" ;
+        lc = wxT("sr_YU") ;
         break ;
       case verSlovenian:
-        lc = "sl_SI" ;
+        lc = wxT("sl_SI") ;
         break ;
       case verMacedonian:
-        lc = "mk_MK" ;
+        lc = wxT("mk_MK") ;
         break ;
       case verCroatia:
-        lc = "hr_HR" ;
+        lc = wxT("hr_HR") ;
         break ;
       case verBrazil:
-        lc = "pt_BR " ;
+        lc = wxT("pt_BR ") ;
         break ;
       case verBulgaria:
-        lc = "bg_BG" ;
+        lc = wxT("bg_BG") ;
         break ;
       case verCatalonia:
-        lc = "ca_ES" ;
+        lc = wxT("ca_ES") ;
         break ;
       case verScottishGaelic:
-        lc = "gd" ;
+        lc = wxT("gd") ;
         break ;
       case verManxGaelic:
-        lc = "gv" ;
+        lc = wxT("gv") ;
         break ;
       case verBreton:
-        lc = "br" ;
+        lc = wxT("br") ;
         break ;
       case verNunavut:
-        lc = "iu_CA" ;
+        lc = wxT("iu_CA") ;
         break ;
       case verWelsh:
-        lc = "cy" ;
+        lc = wxT("cy") ;
         break ;
       case verIrishGaelicScript:
-        lc = "ga_IE" ;
+        lc = wxT("ga_IE") ;
         break ;
       case verEngCanada:
-        lc = "en_CA" ;
+        lc = wxT("en_CA") ;
         break ;
       case verBhutan:
-        lc = "dz_BT" ;
+        lc = wxT("dz_BT") ;
         break ;
       case verArmenian:
-        lc = "hy_AM" ;
+        lc = wxT("hy_AM") ;
         break ;
       case verGeorgian:
-        lc = "ka_GE" ;
+        lc = wxT("ka_GE") ;
         break ;
       case verSpLatinAmerica:
-        lc = "es_AR" ;
+        lc = wxT("es_AR") ;
         break ;
       case verTonga:
-        lc = "to_TO" ;
+        lc = wxT("to_TO" );
         break ;
       case verFrenchUniversal:
-        lc = "fr_FR" ;
+        lc = wxT("fr_FR") ;
         break ;
       case verAustria:
-        lc = "de_AT" ;
+        lc = wxT("de_AT") ;
         break ;
       case verGujarati:
-        lc = "gu_IN" ;
+        lc = wxT("gu_IN") ;
         break ;
       case verPunjabi:
-        lc = "pa" ;
+        lc = wxT("pa") ;
         break ;
       case verIndiaUrdu:
-        lc = "ur_IN" ;
+        lc = wxT("ur_IN") ;
         break ;
       case verVietnam:
-        lc = "vi_VN" ;
+        lc = wxT("vi_VN") ;
         break ;
       case verFrBelgium:
-        lc = "fr_BE" ;
+        lc = wxT("fr_BE") ;
         break ;
       case verUzbek:
-        lc = "uz_UZ" ;
+        lc = wxT("uz_UZ") ;
         break ;
       case verSingapore:
-        lc = "zh_SG" ;
+        lc = wxT("zh_SG") ;
         break ;
       case verNynorsk:
-        lc = "nn_NO" ;
+        lc = wxT("nn_NO") ;
         break ;
       case verAfrikaans:
-        lc = "af_ZA" ;
+        lc = wxT("af_ZA") ;
         break ;
       case verEsperanto:
-        lc = "eo" ;
+        lc = wxT("eo") ;
         break ;
       case verMarathi:
-        lc = "mr_IN" ;
+        lc = wxT("mr_IN") ;
         break ;
       case verTibetan:
-        lc = "bo" ;
+        lc = wxT("bo") ;
         break ;
       case verNepal:
-        lc = "ne_NP" ;
+        lc = wxT("ne_NP") ;
         break ;
       case verGreenland:
-        lc = "kl_GL" ;
+        lc = wxT("kl_GL") ;
         break ;
       default :
         break ;
@@ -1348,6 +1396,17 @@ wxFontEncoding wxLocale::GetSystemEncoding()
         wxFontEncoding enc = wxFontMapper::Get()->
             CharsetToEncoding(encname, FALSE /* not interactive */);
 
+        // on some modern Linux systems (RedHat 8) the default system locale
+        // is UTF8 -- but it isn't supported by wxGTK in ANSI build at all so
+        // don't even try to use it in this case
+#if !wxUSE_UNICODE
+        if ( enc == wxFONTENCODING_UTF8 )
+        {
+            // the most similar supported encoding...
+            enc = wxFONTENCODING_ISO8859_1;
+        }
+#endif // !wxUSE_UNICODE
+
         // this should probably be considered as a bug in CharsetToEncoding():
         // it shouldn't return wxFONTENCODING_DEFAULT at all - but it does it
         // for US-ASCII charset
@@ -1365,12 +1424,76 @@ wxFontEncoding wxLocale::GetSystemEncoding()
     return wxFONTENCODING_SYSTEM;
 }
 
-/*static*/ void wxLocale::AddLanguage(const wxLanguageInfo& info)
+/* static */
+void wxLocale::AddLanguage(const wxLanguageInfo& info)
 {
     CreateLanguagesDB();
     ms_languagesDB->Add(info);
 }
 
+/* static */
+const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang)
+{
+    CreateLanguagesDB();
+
+    const size_t count = ms_languagesDB->GetCount();
+    for ( size_t i = 0; i < count; i++ )
+    {
+        if ( ms_languagesDB->Item(i).Language == lang )
+        {
+            return &ms_languagesDB->Item(i);
+        }
+    }
+
+    return NULL;
+}
+
+/* static */
+wxString wxLocale::GetLanguageName(int lang)
+{
+    const wxLanguageInfo *info = GetLanguageInfo(lang);
+    if ( !info )
+        return wxEmptyString;
+    else
+        return info->Description;
+}
+
+/* static */
+const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale)
+{
+    CreateLanguagesDB();
+
+    const wxLanguageInfo *infoRet = NULL;
+
+    const size_t count = ms_languagesDB->GetCount();
+    for ( size_t i = 0; i < count; i++ )
+    {
+        const wxLanguageInfo *info = &ms_languagesDB->Item(i);
+
+        if ( wxStricmp(locale, info->CanonicalName) == 0 ||
+                wxStricmp(locale, info->Description) == 0 )
+        {
+            // exact match, stop searching
+            infoRet = info;
+            break;
+        }
+
+        if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 )
+        {
+            // a match -- but maybe we'll find an exact one later, so continue
+            // looking
+            //
+            // OTOH, maybe we had already found a language match and in this
+            // case don't overwrite it becauce the entry for the default
+            // country always appears first in ms_languagesDB
+            if ( !infoRet )
+                infoRet = info;
+        }
+    }
+
+    return infoRet;
+}
+
 wxString wxLocale::GetSysName() const
 {
     return wxSetlocale(LC_ALL, NULL);
@@ -1390,6 +1513,7 @@ wxLocale::~wxLocale()
     // restore old locale
     wxSetLocale(m_pOldLocale);
     wxSetlocale(LC_ALL, m_pszOldLocale);
+    free((wxChar *)m_pszOldLocale);     // const_cast
 }
 
 // get the translation of given string in current locale
@@ -2091,7 +2215,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule)
 #define LNG(wxlang, canonical, winlang, winsublang, desc) \
     info.Language = wxlang;                               \
     info.CanonicalName = wxT(canonical);                  \
-    info.Description = desc;                              \
+    info.Description = wxT(desc);                         \
     SETWINLANG(info, winlang, winsublang)                 \
     AddLanguage(info);
 
@@ -2100,7 +2224,7 @@ void wxLocale::InitLanguagesDB()
    wxLanguageInfo info;
    wxStringTokenizer tkn;
 
-      LNG(wxLANGUAGE_ABKHAZIAN,                  "ab"   , 0              , 0                                 , "Abkhazian")
+   LNG(wxLANGUAGE_ABKHAZIAN,                  "ab"   , 0              , 0                                 , "Abkhazian")
    LNG(wxLANGUAGE_AFAR,                       "aa"   , 0              , 0                                 , "Afar")
    LNG(wxLANGUAGE_AFRIKAANS,                  "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT                   , "Afrikaans")
    LNG(wxLANGUAGE_ALBANIAN,                   "sq_AL", LANG_ALBANIAN  , SUBLANG_DEFAULT                   , "Albanian")
@@ -2143,11 +2267,11 @@ void wxLocale::InitLanguagesDB()
    LNG(wxLANGUAGE_CATALAN,                    "ca_ES", LANG_CATALAN   , SUBLANG_DEFAULT                   , "Catalan")
    LNG(wxLANGUAGE_CHINESE,                    "zh_CN", LANG_CHINESE   , SUBLANG_DEFAULT                   , "Chinese")
    LNG(wxLANGUAGE_CHINESE_SIMPLIFIED,         "zh_CN", LANG_CHINESE   , SUBLANG_CHINESE_SIMPLIFIED        , "Chinese (Simplified)")
-   LNG(wxLANGUAGE_CHINESE_TRADITIONAL,        "zh_CN", LANG_CHINESE   , SUBLANG_CHINESE_TRADITIONAL       , "Chinese (Traditional)")
+   LNG(wxLANGUAGE_CHINESE_TRADITIONAL,        "zh_TW", LANG_CHINESE   , SUBLANG_CHINESE_TRADITIONAL       , "Chinese (Traditional)")
    LNG(wxLANGUAGE_CHINESE_HONGKONG,           "zh_HK", LANG_CHINESE   , SUBLANG_CHINESE_HONGKONG          , "Chinese (Hongkong)")
    LNG(wxLANGUAGE_CHINESE_MACAU,              "zh_MO", LANG_CHINESE   , SUBLANG_CHINESE_MACAU             , "Chinese (Macau)")
    LNG(wxLANGUAGE_CHINESE_SINGAPORE,          "zh_SG", LANG_CHINESE   , SUBLANG_CHINESE_SINGAPORE         , "Chinese (Singapore)")
-   LNG(wxLANGUAGE_CHINESE_TAIWAN,             "zh_TW", 0              , 0                                 , "Chinese (Taiwan)")
+   LNG(wxLANGUAGE_CHINESE_TAIWAN,             "zh_TW", LANG_CHINESE   , SUBLANG_CHINESE_TRADITIONAL       , "Chinese (Taiwan)")
    LNG(wxLANGUAGE_CORSICAN,                   "co"   , 0              , 0                                 , "Corsican")
    LNG(wxLANGUAGE_CROATIAN,                   "hr_HR", LANG_CROATIAN  , SUBLANG_DEFAULT                   , "Croatian")
    LNG(wxLANGUAGE_CZECH,                      "cs_CZ", LANG_CZECH     , SUBLANG_DEFAULT                   , "Czech")
@@ -2241,7 +2365,7 @@ void wxLocale::InitLanguagesDB()
    LNG(wxLANGUAGE_NAURU,                      "na"   , 0              , 0                                 , "Nauru")
    LNG(wxLANGUAGE_NEPALI,                     "ne"   , LANG_NEPALI    , SUBLANG_DEFAULT                   , "Nepali")
    LNG(wxLANGUAGE_NEPALI_INDIA,               "ne_IN", LANG_NEPALI    , SUBLANG_NEPALI_INDIA              , "Nepali (India)")
-   LNG(wxLANGUAGE_NORWEGIAN_BOKMAL,           "no_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL          , "Norwegian (Bokmal)")
+   LNG(wxLANGUAGE_NORWEGIAN_BOKMAL,           "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL          , "Norwegian (Bokmal)")
    LNG(wxLANGUAGE_NORWEGIAN_NYNORSK,          "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK         , "Norwegian (Nynorsk)")
    LNG(wxLANGUAGE_OCCITAN,                    "oc"   , 0              , 0                                 , "Occitan")
    LNG(wxLANGUAGE_ORIYA,                      "or"   , LANG_ORIYA     , SUBLANG_DEFAULT                   , "Oriya")