]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/intl.cpp
XRC needs wxXML, check it
[wxWidgets.git] / src / common / intl.cpp
index 17900a64757451a06cb1c3692092792ca33504f2..d3823ead815d958aeee1071ba08656eaad8d587c 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        src/common/intl.cpp
-// Purpose:     Internationalization and localisation for wxWindows
+// Purpose:     Internationalization and localisation for wxWidgets
 // Author:      Vadim Zeitlin
 // Modified by: Michael N. Filippov <michael@idisys.iae.nsk.su>
 //              (2003/09/30 - PluralForms support)
     #pragma implementation "intl.h"
 #endif
 
+#if defined(__BORLAND__) && !defined(__WXDEBUG__)
+    // There's a bug in Borland's compiler that breaks wxLocale with -O2,
+    // so make sure that flag is not used for this file:
+    #pragma option -O1
+#endif
+
+#ifdef __EMX__
+// The following define is needed by Innotek's libc to
+// make the definition of struct localeconv available.
+#define __INTERNAL_DEFS
+#endif
+
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
@@ -43,7 +55,7 @@
   #include <langinfo.h>
 #endif
 
-// wxWindows
+// wxWidgets
 #ifndef WX_PRECOMP
     #include "wx/string.h"
     #include "wx/intl.h"
@@ -151,7 +163,7 @@ static inline wxString ExtractNotLang(const wxString& langFull)
 // Plural forms parser
 // ----------------------------------------------------------------------------
 
-/* 
+/*
                                 Simplified Grammar
 
 Expression:
@@ -177,7 +189,7 @@ RelationalExpression:
     MultiplicativeExpression ">=" MultiplicativeExpression
     MultiplicativeExpression "<=" MultiplicativeExpression
     MultiplicativeExpression
-    
+
 MultiplicativeExpression:
     PmExpression '%' PmExpression
     PmExpression
@@ -389,7 +401,7 @@ private:
     wxPluralFormsToken m_token;
     wxPluralFormsNodePtr m_nodes[3];
 };
-    
+
 wxPluralFormsNodePtr::~wxPluralFormsNodePtr()
 {
     delete m_p;
@@ -474,7 +486,7 @@ class wxPluralFormsCalculator
 {
 public:
     wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {}
-    
+
     // input: number, returns msgstr index
     int evaluate(int n) const;
 
@@ -487,7 +499,7 @@ public:
 
     void  init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural);
     wxString getString() const;
-    
+
 private:
     wxPluralFormsToken::Number m_nplurals;
     wxPluralFormsNodePtr m_plural;
@@ -529,7 +541,7 @@ private:
     wxPluralFormsScanner& m_scanner;
     const wxPluralFormsToken& token() const;
     bool nextToken();
-    
+
     wxPluralFormsNode* expression();
     wxPluralFormsNode* logicalOrExpression();
     wxPluralFormsNode* logicalAndExpression();
@@ -875,7 +887,8 @@ public:
               wxPluralFormsCalculatorPtr& rPluralFormsCalculator);
 
     // fills the hash with string-translation pairs
-    void FillHash(wxMessagesHash& hash, bool convertEncoding) const;
+    void FillHash(wxMessagesHash& hash, const wxString& msgIdCharset,
+                  bool convertEncoding) const;
 
 private:
     // this implementation is binary compatible with GNU gettext() version 0.10
@@ -911,7 +924,7 @@ private:
                      *m_pTransTable;  //            translated
 
     wxString m_charset;
-                     
+
     // swap the 2 halves of 32 bit integer if needed
     size_t32 Swap(size_t32 ui) const
     {
@@ -932,7 +945,7 @@ private:
         }
 
         return (const char *)(m_pData + ofsString);
-    }    
+    }
 
     bool m_bSwapped;   // wrong endianness?
 
@@ -951,7 +964,8 @@ class wxMsgCatalog
 {
 public:
     // load the catalog from disk (szDirPrefix corresponds to language)
-    bool Load(const wxChar *szDirPrefix, const wxChar *szName, bool bConvertEncoding = FALSE);
+    bool Load(const wxChar *szDirPrefix, const wxChar *szName,
+              const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false);
 
     // get name of the catalog
     wxString GetName() const { return m_name; }
@@ -1064,7 +1078,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
       FIXME: UNICODE SUPPORT: must use CHARSET specifier!
    */
    wxString szName = szName0;
-   if(szName.Find(wxT('.')) != -1) // contains a dot
+   if(szName.Find(wxT('.')) != wxNOT_FOUND) // contains a dot
       szName = szName.Left(szName.Find(wxT('.')));
 
   wxString searchPath = GetFullSearchPath(szDirPrefix);
@@ -1094,7 +1108,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
   wxString strFullName;
   if ( !wxFindFileInPath(&strFullName, searchPath, strFile) ) {
     wxLogVerbose(_("catalog file for domain '%s' not found."), szName.c_str());
-    return FALSE;
+    return false;
   }
 
   // open file
@@ -1103,18 +1117,18 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
 
   wxFile fileMsg(strFullName);
   if ( !fileMsg.IsOpened() )
-    return FALSE;
+    return false;
 
   // get the file size
   off_t nSize = fileMsg.Length();
   if ( nSize == wxInvalidOffset )
-    return FALSE;
+    return false;
 
   // read the whole file in memory
   m_pData = new size_t8[nSize];
   if ( fileMsg.Read(m_pData, nSize) != nSize ) {
     wxDELETEA(m_pData);
-    return FALSE;
+    return false;
   }
 
   // examine header
@@ -1134,7 +1148,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
     wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str());
 
     wxDELETEA(m_pData);
-    return FALSE;
+    return false;
   }
 
   // initialize
@@ -1144,7 +1158,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
   m_pTransTable = (wxMsgTableEntry *)(m_pData +
                    Swap(pHeader->ofsTransTable));
   m_nSize = nSize;
-    
+
   // now parse catalog's header and try to extract catalog charset and
   // plural forms formula from it:
 
@@ -1169,7 +1183,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
           }
       }
       // else: incorrectly filled Content-Type header
-      
+
       // Extract plural forms:
       begin = header.Find(wxT("Plural-Forms:"));
       if (begin != wxNOT_FOUND)
@@ -1202,23 +1216,33 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0,
   return true;
 }
 
-void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) const
+void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
+                                const wxString& msgIdCharset,
+                                bool convertEncoding) const
 {
 #if wxUSE_WCHAR_T
     wxCSConv *csConv = NULL;
-    if ( !!m_charset )
+    if ( !m_charset.IsEmpty() )
         csConv = new wxCSConv(m_charset);
 
     wxMBConv& inputConv = csConv ? *((wxMBConv*)csConv) : *wxConvCurrent;
+
+    wxCSConv *sourceConv = NULL;
+    if ( !msgIdCharset.empty() && (m_charset != msgIdCharset) )
+        sourceConv = new wxCSConv(msgIdCharset);
+
 #elif wxUSE_FONTMAP
+    wxASSERT_MSG( msgIdCharset == NULL,
+                  _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") );
+
     wxEncodingConverter converter;
     if ( convertEncoding )
     {
         wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM;
-        wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(charset, FALSE);
+        wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(m_charset, false);
         if ( enc == wxFONTENCODING_SYSTEM )
         {
-            convertEncoding = FALSE; // unknown encoding
+            convertEncoding = false; // unknown encoding
         }
         else
         {
@@ -1228,10 +1252,10 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons
                 wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc);
                 if (a[0] == enc)
                     // no conversion needed, locale uses native encoding
-                    convertEncoding = FALSE;
+                    convertEncoding = false;
                 if (a.GetCount() == 0)
                     // we don't know common equiv. under this platform
-                    convertEncoding = FALSE;
+                    convertEncoding = false;
                 targetEnc = a[0];
             }
         }
@@ -1247,11 +1271,17 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons
     for (size_t i = 0; i < m_numStrings; i++)
     {
         const char *data = StringAtOfs(m_pOrigTable, i);
-#if wxUSE_WCHAR_T
+#if wxUSE_UNICODE
         wxString msgid(data, inputConv);
 #else
-        wxString msgid(data);
+        wxString msgid;
+#if wxUSE_WCHAR_T
+        if ( convertEncoding && sourceConv )
+            msgid = wxString(inputConv.cMB2WC(data), *sourceConv);
+        else
 #endif
+            msgid = data;
+#endif // wxUSE_UNICODE
 
         data = StringAtOfs(m_pTransTable, i);
         size_t length = Swap(m_pTransTable[i].nLen);
@@ -1288,6 +1318,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons
     }
 
 #if wxUSE_WCHAR_T
+    delete sourceConv;
     delete csConv;
 #endif
 }
@@ -1298,7 +1329,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons
 // ----------------------------------------------------------------------------
 
 bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName,
-                        bool bConvertEncoding)
+                        const wxChar *msgIdCharset, bool bConvertEncoding)
 {
     wxMsgCatalogFile file;
 
@@ -1306,11 +1337,11 @@ bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName,
 
     if ( file.Load(szDirPrefix, szName, m_pluralFormsCalculator) )
     {
-        file.FillHash(m_messages, bConvertEncoding);
-        return TRUE;
+        file.FillHash(m_messages, msgIdCharset, bConvertEncoding);
+        return true;
     }
 
-    return FALSE;
+    return false;
 }
 
 const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const
@@ -1364,11 +1395,12 @@ wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL;
 }
 
 
-wxLocale::wxLocale()
+void wxLocale::DoCommonInit()
 {
   m_pszOldLocale = NULL;
   m_pMsgCat = NULL;
   m_language = wxLANGUAGE_UNKNOWN;
+  m_initialized = false;
 }
 
 // NB: this function has (desired) side effect of changing current locale
@@ -1378,6 +1410,10 @@ bool wxLocale::Init(const wxChar *szName,
                     bool        bLoadDefault,
                     bool        bConvertEncoding)
 {
+  wxASSERT_MSG( !m_initialized,
+                _T("you can't call wxLocale::Init more than once") );
+
+  m_initialized = true;
   m_strLocale = szName;
   m_strShort = szShort;
   m_bConvertEncoding = bConvertEncoding;
@@ -1389,7 +1425,7 @@ bool wxLocale::Init(const wxChar *szName,
     // the argument to setlocale()
     szLocale = szShort;
 
-    wxCHECK_MSG( szLocale, FALSE, _T("no locale to set in wxLocale::Init()") );
+    wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") );
   }
 
 #ifdef __WXWINCE__
@@ -1399,7 +1435,7 @@ bool wxLocale::Init(const wxChar *szName,
       256);
   if (ret != 0)
   {
-    m_pszOldLocale = wxStrdup(localeName);      
+    m_pszOldLocale = wxStrdup(localeName);
   }
   else
     m_pszOldLocale = NULL;
@@ -1407,9 +1443,11 @@ bool wxLocale::Init(const wxChar *szName,
   // TODO: how to find languageId
   // SetLocaleInfo(languageId, SORT_DEFAULT, localeName);
 #else
-  m_pszOldLocale = wxSetlocale(LC_ALL, szLocale);
-  if ( m_pszOldLocale )
-      m_pszOldLocale = wxStrdup(m_pszOldLocale);
+  wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale);
+  if ( oldLocale )
+      m_pszOldLocale = wxStrdup(oldLocale);
+  else
+      m_pszOldLocale = NULL;
 #endif
 
   if ( m_pszOldLocale == NULL )
@@ -1420,7 +1458,7 @@ bool wxLocale::Init(const wxChar *szName,
   if ( m_strShort.IsEmpty() ) {
     // FIXME I don't know how these 2 letter abbreviations are formed,
     //       this wild guess is surely wrong
-    if ( szLocale[0] )
+    if ( szLocale && szLocale[0] )
     {
         m_strShort += (wxChar)wxTolower(szLocale[0]);
         if ( szLocale[1] )
@@ -1431,9 +1469,9 @@ bool wxLocale::Init(const wxChar *szName,
   // save the old locale to be able to restore it later
   m_pOldLocale = wxSetLocale(this);
 
-  // load the default catalog with wxWindows standard messages
+  // load the default catalog with wxWidgets standard messages
   m_pMsgCat = NULL;
-  bool bOk = TRUE;
+  bool bOk = true;
   if ( bLoadDefault )
     bOk = AddCatalog(wxT("wxstd"));
 
@@ -1447,24 +1485,24 @@ static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc)
     wxMB2WXbuf l = wxSetlocale(c, lc);
     if ( !l && lc && lc[0] != 0 )
     {
-       wxString buf(lc);
+        wxString buf(lc);
         wxString buf2;
-       buf2 = buf + wxT(".UTF-8");
-       l = wxSetlocale(c, buf2.c_str());
+        buf2 = buf + wxT(".UTF-8");
+        l = wxSetlocale(c, buf2.c_str());
         if ( !l )
         {
             buf2 = buf + wxT(".utf-8");
-           l = wxSetlocale(c, buf2.c_str());
+            l = wxSetlocale(c, buf2.c_str());
         }
         if ( !l )
         {
             buf2 = buf + wxT(".UTF8");
-           l = wxSetlocale(c, buf2.c_str());
+            l = wxSetlocale(c, buf2.c_str());
         }
         if ( !l )
         {
             buf2 = buf + wxT(".utf8");
-           l = wxSetlocale(c, buf2.c_str());
+            l = wxSetlocale(c, buf2.c_str());
         }
     }
     return l;
@@ -1485,7 +1523,7 @@ bool wxLocale::Init(int language, int flags)
     // We failed to detect system language, so we will use English:
     if (lang == wxLANGUAGE_UNKNOWN)
     {
-       return FALSE;
+       return false;
     }
 
     const wxLanguageInfo *info = GetLanguageInfo(lang);
@@ -1494,7 +1532,7 @@ bool wxLocale::Init(int language, int flags)
     if (info == NULL)
     {
         wxLogError(wxT("Unknown language %i."), lang);
-        return FALSE;
+        return false;
     }
 
     wxString name = info->Description;
@@ -1542,7 +1580,7 @@ bool wxLocale::Init(int language, int flags)
     if ( !retloc )
     {
         wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str());
-        return FALSE;
+        return false;
     }
 #elif defined(__WIN32__)
 
@@ -1555,7 +1593,10 @@ bool wxLocale::Init(int language, int flags)
         //     #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow.
         #define SETLOCALE_FAILS_ON_UNICODE_LANGS
     #endif
-    
+
+#if !wxUSE_UNICODE
+    const
+#endif
     wxMB2WXbuf retloc = wxT("C");
     if (language != wxLANGUAGE_DEFAULT)
     {
@@ -1566,7 +1607,7 @@ bool wxLocale::Init(int language, int flags)
         }
         else
         {
-            int codepage 
+            int codepage
                          #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
                          = -1
                          #endif
@@ -1596,7 +1637,7 @@ bool wxLocale::Init(int language, int flags)
             {
                 wxLogLastError(wxT("SetThreadLocale"));
                 wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
-                return FALSE;
+                return false;
             }
             else
             {
@@ -1638,12 +1679,12 @@ bool wxLocale::Init(int language, int flags)
     if ( !retloc )
     {
         wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
-        return FALSE;
+        return false;
     }
 #elif defined(__WXMAC__) || defined(__WXPM__)
     wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString);
 #else
-    return FALSE;
+    return false;
     #define WX_NO_LOCALE_SUPPORT
 #endif
 
@@ -1654,7 +1695,7 @@ bool wxLocale::Init(int language, int flags)
                     (flags & wxLOCALE_CONV_ENCODING) != 0);
     free(szLocale);
 
-    if ( ret )
+    if (IsOk()) // setlocale() succeeded
         m_language = lang;
 
     return ret;
@@ -2129,7 +2170,7 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix)
 
 // this is a bit strange as under Windows we get the encoding name using its
 // numeric value and under Unix we do it the other way round, but this just
-// reflects the way different systems provide he encoding info
+// reflects the way different systems provide the encoding info
 
 /* static */
 wxString wxLocale::GetSystemEncodingName()
@@ -2161,8 +2202,18 @@ wxString wxLocale::GetSystemEncodingName()
         // ISO-646, i.e. 7 bit ASCII
         //
         // and recent glibc call it ANSI_X3.4-1968...
-        if ( strcmp(alang, "646") == 0 ||
-               strcmp(alang, "ANSI_X3.4-1968") == 0 )
+        //
+        // HP-UX uses HP-Roman8 cset which is not the same as ASCII (see RFC
+        // 1345 for its definition) but must be recognized as otherwise HP
+        // users get a warning about it on each program startup, so handle it
+        // here -- but it would be obviously better to add real supprot to it,
+        // of course!
+        if ( strcmp(alang, "646") == 0
+                || strcmp(alang, "ANSI_X3.4-1968") == 0
+#ifdef __HPUX__
+                    || strcmp(alang, "roman8") == 0
+#endif // __HPUX__
+            )
         {
             encname = _T("US-ASCII");
         }
@@ -2208,7 +2259,7 @@ wxFontEncoding wxLocale::GetSystemEncoding()
 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
     UINT codepage = ::GetACP();
 
-    // wxWindows only knows about CP1250-1257, 932, 936, 949, 950
+    // wxWidgets only knows about CP1250-1257, 932, 936, 949, 950
     if ( codepage >= 1250 && codepage <= 1257 )
     {
         return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250);
@@ -2233,12 +2284,20 @@ wxFontEncoding wxLocale::GetSystemEncoding()
     {
         return wxFONTENCODING_CP950;
     }
+#elif defined(__WXMAC__)
+    TextEncoding encoding = 0 ;
+#if TARGET_CARBON
+    encoding = CFStringGetSystemEncoding() ;
+#else
+    UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ;
+#endif
+    return wxMacGetFontEncFromSystemEnc( encoding ) ;
 #elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP
     wxString encname = GetSystemEncodingName();
     if ( !encname.empty() )
     {
         wxFontEncoding enc = wxFontMapper::Get()->
-            CharsetToEncoding(encname, FALSE /* not interactive */);
+            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
@@ -2280,6 +2339,11 @@ const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang)
 {
     CreateLanguagesDB();
 
+    // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so
+    // make it work
+    if ( lang == wxLANGUAGE_DEFAULT )
+        lang = GetSystemLanguage();
+
     const size_t count = ms_languagesDB->GetCount();
     for ( size_t i = 0; i < count; i++ )
     {
@@ -2415,15 +2479,16 @@ const wxChar *wxLocale::GetString(const wxChar *szOrigString,
             if ( szDomain != NULL )
             {
                 wxLogTrace(_T("i18n"),
-                           _T("string '%s'[%d] not found in domain '%s' for locale '%s'."),
-                           szOrigString, n, szDomain, m_strLocale.c_str());
+                           _T("string '%s'[%lu] not found in domain '%s' for locale '%s'."),
+                           szOrigString, (unsigned long)n,
+                           szDomain, m_strLocale.c_str());
 
             }
             else
             {
                 wxLogTrace(_T("i18n"),
-                           _T("string '%s'[%d] not found in locale '%s'."),
-                           szOrigString, n, m_strLocale.c_str());
+                           _T("string '%s'[%lu] not found in locale '%s'."),
+                           szOrigString, (unsigned long)n, m_strLocale.c_str());
             }
         }
 #endif // __WXDEBUG__
@@ -2437,6 +2502,58 @@ const wxChar *wxLocale::GetString(const wxChar *szOrigString,
     return pszTrans;
 }
 
+wxString wxLocale::GetHeaderValue( const wxChar* szHeader,
+                                   const wxChar* szDomain ) const
+{
+    if ( wxIsEmpty(szHeader) )
+        return wxEmptyString;
+
+    wxChar const * pszTrans = NULL;
+    wxMsgCatalog *pMsgCat;
+
+    if ( szDomain != NULL )
+    {
+        pMsgCat = FindCatalog(szDomain);
+
+        // does the catalog exist?
+        if ( pMsgCat == NULL )
+            return wxEmptyString;
+
+        pszTrans = pMsgCat->GetString(wxT(""), (size_t)-1);
+    }
+    else
+    {
+        // search in all domains
+        for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
+        {
+            pszTrans = pMsgCat->GetString(wxT(""), (size_t)-1);
+            if ( pszTrans != NULL )   // take the first found
+                break;
+        }
+    }
+
+    if ( wxIsEmpty(pszTrans) )
+      return wxEmptyString;
+
+    wxChar const * pszFound = wxStrstr(pszTrans, szHeader);
+    if ( pszFound == NULL )
+      return wxEmptyString;
+
+    pszFound += wxStrlen(szHeader) + 2 /* ': ' */;
+
+    // Every header is separated by \n
+
+    wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n'));
+    if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound);
+
+
+    // wxString( wxChar*, length);
+    wxString retVal( pszFound, pszEndLine - pszFound );
+
+    return retVal;
+}
+
+
 // find catalog by name in a linked list, return NULL if !found
 wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const
 {
@@ -2459,22 +2576,47 @@ bool wxLocale::IsLoaded(const wxChar *szDomain) const
 
 // add a catalog to our linked list
 bool wxLocale::AddCatalog(const wxChar *szDomain)
+{
+    return AddCatalog(szDomain, wxLANGUAGE_ENGLISH, NULL);
+}
+
+// add a catalog to our linked list
+bool wxLocale::AddCatalog(const wxChar *szDomain,
+                          wxLanguage    msgIdLanguage,
+                          const wxChar *msgIdCharset)
+
 {
   wxMsgCatalog *pMsgCat = new wxMsgCatalog;
 
-  if ( pMsgCat->Load(m_strShort, szDomain, m_bConvertEncoding) ) {
+  if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, m_bConvertEncoding) ) {
     // add it to the head of the list so that in GetString it will
     // be searched before the catalogs added earlier
     pMsgCat->m_pNext = m_pMsgCat;
     m_pMsgCat = pMsgCat;
 
-    return TRUE;
+    return true;
   }
   else {
     // don't add it because it couldn't be loaded anyway
     delete pMsgCat;
 
-    return FALSE;
+    // It is OK to not load catalog if the msgid language and m_language match,
+    // in which case we can directly display the texts embedded in program's
+    // source code:
+    if (m_language == msgIdLanguage)
+        return true;
+
+    // If there's no exact match, we may still get partial match where the
+    // (basic) language is same, but the country differs. For example, it's
+    // permitted to use en_US strings from sources even if m_language is en_GB:
+    const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage);
+    if ( msgIdLangInfo &&
+         msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) )
+    {
+        return true;
+    }
+
+    return false;
   }
 }
 
@@ -2482,12 +2624,10 @@ bool wxLocale::AddCatalog(const wxChar *szDomain)
 // accessors for locale-dependent data
 // ----------------------------------------------------------------------------
 
-#if 0
-
 #ifdef __WXMSW__
 
 /* static */
-wxString wxLocale::GetInfo(wxLocaleInfo index)
+wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat))
 {
     wxString str;
     wxChar buffer[256];
@@ -2495,29 +2635,31 @@ wxString wxLocale::GetInfo(wxLocaleInfo index)
     buffer[0] = wxT('\0');
     switch (index)
     {
-        case wxSYS_DECIMAL_SEPARATOR:
+        case wxLOCALE_DECIMAL_POINT:
             count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buffer, 256);
             if (!count)
-                str << ".";
+                str << wxT(".");
             else
                 str << buffer;
             break;
+#if 0
         case wxSYS_LIST_SEPARATOR:
             count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, buffer, 256);
             if (!count)
-                str << ",";
+                str << wxT(",");
             else
                 str << buffer;
             break;
         case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero
             count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILZERO, buffer, 256);
             if (!count)
-                str << "0";
+                str << wxT("0");
             else
                 str << buffer;
             break;
+#endif
         default:
-            wxFAIL_MSG("Unknown System String !");
+            wxFAIL_MSG(wxT("Unknown System String !"));
     }
     return str;
 }
@@ -2525,15 +2667,42 @@ wxString wxLocale::GetInfo(wxLocaleInfo index)
 #else // !__WXMSW__
 
 /* static */
-wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory)
+wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat)
 {
-    return wxEmptyString;
+    struct lconv *locale_info = localeconv();
+    switch (cat)
+    {
+        case wxLOCALE_CAT_NUMBER:
+            switch (index)
+            {
+                case wxLOCALE_THOUSANDS_SEP:
+                    return wxString(locale_info->thousands_sep,
+                                    *wxConvCurrent);
+                case wxLOCALE_DECIMAL_POINT:
+                    return wxString(locale_info->decimal_point,
+                                    *wxConvCurrent);
+                default:
+                    return wxEmptyString;
+            }
+        case wxLOCALE_CAT_MONEY:
+            switch (index)
+            {
+                case wxLOCALE_THOUSANDS_SEP:
+                    return wxString(locale_info->mon_thousands_sep,
+                                    *wxConvCurrent);
+                case wxLOCALE_DECIMAL_POINT:
+                    return wxString(locale_info->mon_decimal_point,
+                                    *wxConvCurrent);
+                default:
+                    return wxEmptyString;
+            }
+        default:
+            return wxEmptyString;
+    }
 }
 
 #endif // __WXMSW__/!__WXMSW__
 
-#endif // 0
-
 // ----------------------------------------------------------------------------
 // global functions and variables
 // ----------------------------------------------------------------------------
@@ -2567,7 +2736,7 @@ class wxLocaleModule: public wxModule
     DECLARE_DYNAMIC_CLASS(wxLocaleModule)
     public:
         wxLocaleModule() {}
-        bool OnInit() { return TRUE; }
+        bool OnInit() { return true; }
         void OnExit() { wxLocale::DestroyLanguagesDB(); }
 };
 
@@ -3129,7 +3298,7 @@ void wxLocale::InitLanguagesDB()
    LNG(wxLANGUAGE_BURMESE,                    "my"   , 0              , 0                                 , "Burmese")
    LNG(wxLANGUAGE_CAMBODIAN,                  "km"   , 0              , 0                                 , "Cambodian")
    LNG(wxLANGUAGE_CATALAN,                    "ca_ES", LANG_CATALAN   , SUBLANG_DEFAULT                   , "Catalan")
-   LNG(wxLANGUAGE_CHINESE,                    "zh_CN", LANG_CHINESE   , SUBLANG_DEFAULT                   , "Chinese")
+   LNG(wxLANGUAGE_CHINESE,                    "zh_TW", LANG_CHINESE   , SUBLANG_DEFAULT                   , "Chinese")
    LNG(wxLANGUAGE_CHINESE_SIMPLIFIED,         "zh_CN", LANG_CHINESE   , SUBLANG_CHINESE_SIMPLIFIED        , "Chinese (Simplified)")
    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)")
@@ -3286,7 +3455,7 @@ void wxLocale::InitLanguagesDB()
    LNG(wxLANGUAGE_SWAHILI,                    "sw_KE", LANG_SWAHILI   , SUBLANG_DEFAULT                   , "Swahili")
    LNG(wxLANGUAGE_SWEDISH,                    "sv_SE", LANG_SWEDISH   , SUBLANG_SWEDISH                   , "Swedish")
    LNG(wxLANGUAGE_SWEDISH_FINLAND,            "sv_FI", LANG_SWEDISH   , SUBLANG_SWEDISH_FINLAND           , "Swedish (Finland)")
-   LNG(wxLANGUAGE_TAGALOG,                    "tl"   , 0              , 0                                 , "Tagalog")
+   LNG(wxLANGUAGE_TAGALOG,                    "tl_PH", 0              , 0                                 , "Tagalog")
    LNG(wxLANGUAGE_TAJIK,                      "tg"   , 0              , 0                                 , "Tajik")
    LNG(wxLANGUAGE_TAMIL,                      "ta"   , LANG_TAMIL     , SUBLANG_DEFAULT                   , "Tamil")
    LNG(wxLANGUAGE_TATAR,                      "tt"   , LANG_TATAR     , SUBLANG_DEFAULT                   , "Tatar")