]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/intl.cpp
wxDL_XXX macros and dynamic loading cleanup:
[wxWidgets.git] / src / common / intl.cpp
index 4915e52efe3c8de0ccab96e3663aa47033f03aac..0a027c9971795319ac8095aa902605fa48a1bd5a 100644 (file)
 // headers
 // ----------------------------------------------------------------------------
 
-#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.
@@ -75,6 +69,7 @@
 #include "wx/ptr_scpd.h"
 #include "wx/apptrait.h"
 #include "wx/stdpaths.h"
+#include "wx/hashset.h"
 
 #if defined(__WXMAC__)
     #include  "wx/mac/private.h"  // includes mac headers
@@ -878,7 +873,7 @@ public:
    ~wxMsgCatalogFile();
 
     // load the catalog from disk (szDirPrefix corresponds to language)
-    bool Load(const wxChar *szDirPrefix, const wxChar *szName,
+    bool Load(const wxString& szDirPrefix, const wxString& szName,
               wxPluralFormsCalculatorPtr& rPluralFormsCalculator);
 
     // fills the hash with string-translation pairs
@@ -968,14 +963,14 @@ public:
     ~wxMsgCatalog();
 
     // load the catalog from disk (szDirPrefix corresponds to language)
-    bool Load(const wxChar *szDirPrefix, const wxChar *szName,
-              const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false);
+    bool Load(const wxString& dirPrefix, const wxString& name,
+              const wxString& msgIdCharset, bool bConvertEncoding = false);
 
     // get name of the catalog
     wxString GetName() const { return m_name; }
 
     // get the translated string: returns NULL if not found
-    const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const;
+    const wxString *GetString(const wxString& sz, size_t n = size_t(-1)) const;
 
     // public variable pointing to the next element in a linked list (or NULL)
     wxMsgCatalog *m_pNext;
@@ -1017,26 +1012,32 @@ wxMsgCatalogFile::~wxMsgCatalogFile()
     delete [] m_pData;
 }
 
-// return the directory to search for message catalogs under the given prefix
+// return the directories to search for message catalogs under the given
+// prefix, separated by wxPATH_SEP
 static
-wxString GetMsgCatalogSubdir(const wxChar *prefix, const wxChar *lang)
+wxString GetMsgCatalogSubdirs(const wxString& prefix, const wxString& lang)
 {
     wxString searchPath;
     searchPath << prefix << wxFILE_SEP_PATH << lang;
 
-    // under Unix, the message catalogs are supposed to go into LC_MESSAGES
-    // subdirectory so look there too
-#ifdef __UNIX__
+    // Under Unix, the message catalogs are supposed to go into LC_MESSAGES
+    // subdirectory so look there too. Note that we do it on all platforms
+    // and not just Unix, because it doesn't cost much to look into one more
+    // directory and doing it this way has two important benefits:
+    // a) we don't break compatibility with wx-2.6 and older by stopping to
+    //    look in a directory where the catalogs used to be and thus silently
+    //    breaking apps after they are recompiled against the latest wx
+    // b) it makes it possible to package app's support files in the same
+    //    way on all target platforms
     const wxString searchPathOrig(searchPath);
     searchPath << wxFILE_SEP_PATH << wxT("LC_MESSAGES")
                << wxPATH_SEP << searchPathOrig;
-#endif // __UNIX__
 
     return searchPath;
 }
 
 // construct the search path for the given language
-static wxString GetFullSearchPath(const wxChar *lang)
+static wxString GetFullSearchPath(const wxString& lang)
 {
     // first take the entries explicitly added by the program
     wxArrayString paths;
@@ -1045,7 +1046,7 @@ static wxString GetFullSearchPath(const wxChar *lang)
            count = gs_searchPrefixes.size();
     for ( n = 0; n < count; n++ )
     {
-        paths.Add(GetMsgCatalogSubdir(gs_searchPrefixes[n], lang));
+        paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang));
     }
 
 
@@ -1065,7 +1066,7 @@ static wxString GetFullSearchPath(const wxChar *lang)
     const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH"));
     if ( pszLcPath )
     {
-        const wxString lcp = GetMsgCatalogSubdir(pszLcPath, lang);
+        const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang);
         if ( paths.Index(lcp) == wxNOT_FOUND )
             paths.Add(lcp);
     }
@@ -1074,7 +1075,7 @@ static wxString GetFullSearchPath(const wxChar *lang)
     wxString wxp = wxGetInstallPrefix();
     if ( !wxp.empty() )
     {
-        wxp = GetMsgCatalogSubdir(wxp + _T("/share/locale"), lang);
+        wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang);
         if ( paths.Index(wxp) == wxNOT_FOUND )
             paths.Add(wxp);
     }
@@ -1096,7 +1097,7 @@ static wxString GetFullSearchPath(const wxChar *lang)
 }
 
 // open disk file and read in it's contents
-bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName,
+bool wxMsgCatalogFile::Load(const wxString& szDirPrefix, const wxString& szName,
                             wxPluralFormsCalculatorPtr& rPluralFormsCalculator)
 {
   wxString searchPath;
@@ -1117,15 +1118,14 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName,
 
 
   searchPath += GetFullSearchPath(szDirPrefix);
-  const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_'));
-  if ( sublocale )
+  size_t sublocaleIndex = szDirPrefix.find(wxT('_'));
+  if ( sublocaleIndex != wxString::npos )
   {
       // also add just base locale name: for things like "fr_BE" (belgium
       // french) we should use "fr" if no belgium specific message catalogs
       // exist
       searchPath << wxPATH_SEP
-                 << GetFullSearchPath(wxString(szDirPrefix).
-                                      Left((size_t)(sublocale - szDirPrefix)));
+                 << GetFullSearchPath(szDirPrefix.Left(sublocaleIndex));
   }
 
   // don't give translation errors here because the wxstd catalog might
@@ -1304,7 +1304,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
                             : new wxCSConv(msgIdCharset);
 
 #elif wxUSE_FONTMAP
-    wxASSERT_MSG( msgIdCharset == NULL,
+    wxASSERT_MSG( msgIdCharset.empty(),
                   _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") );
 
     wxEncodingConverter converter;
@@ -1374,7 +1374,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
                 msgstr = str;
 #else // !wxUSE_WCHAR_T
         #if wxUSE_FONTMAP
-            if ( convertEncoding )
+            if ( bConvertEncoding )
                 msgstr = wxString(converter.Convert(str));
             else
         #endif
@@ -1418,14 +1418,14 @@ wxMsgCatalog::~wxMsgCatalog()
     }
 }
 
-bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName,
-                        const wxChar *msgIdCharset, bool bConvertEncoding)
+bool wxMsgCatalog::Load(const wxString& dirPrefix, const wxString& name,
+                        const wxString& msgIdCharset, bool bConvertEncoding)
 {
     wxMsgCatalogFile file;
 
-    m_name = szName;
+    m_name = name;
 
-    if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) )
+    if ( !file.Load(dirPrefix, name, m_pluralFormsCalculator) )
         return false;
 
     file.FillHash(m_messages, msgIdCharset, bConvertEncoding);
@@ -1449,7 +1449,7 @@ bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName,
     return true;
 }
 
-const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const
+const wxString *wxMsgCatalog::GetString(const wxString& str, size_t n) const
 {
     int index = 0;
     if (n != size_t(-1))
@@ -1459,16 +1459,16 @@ const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const
     wxMessagesHash::const_iterator i;
     if (index != 0)
     {
-        i = m_messages.find(wxString(sz) + wxChar(index));   // plural
+        i = m_messages.find(wxString(str) + wxChar(index));   // plural
     }
     else
     {
-        i = m_messages.find(sz);
+        i = m_messages.find(str);
     }
 
     if ( i != m_messages.end() )
     {
-        return i->second.c_str();
+        return &i->second;
     }
     else
         return NULL;
@@ -1512,28 +1512,30 @@ void wxLocale::DoCommonInit()
 }
 
 // NB: this function has (desired) side effect of changing current locale
-bool wxLocale::Init(const wxChar *szName,
-                    const wxChar *szShort,
-                    const wxChar *szLocale,
-                    bool        bLoadDefault,
-                    bool        bConvertEncoding)
+bool wxLocale::Init(const wxString& name,
+                    const wxString& shortName,
+                    const wxString& locale,
+                    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_strLocale = name;
+  m_strShort = shortName;
   m_bConvertEncoding = bConvertEncoding;
   m_language = wxLANGUAGE_UNKNOWN;
 
   // change current locale (default: same as long name)
-  if ( szLocale == NULL )
+  wxString szLocale(locale);
+  if ( szLocale.empty() )
   {
     // the argument to setlocale()
-    szLocale = szShort;
+    szLocale = shortName;
 
-    wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") );
+    wxCHECK_MSG( !szLocale.empty(), false,
+                 _T("no locale to set in wxLocale::Init()") );
   }
 
 #ifdef __WXWINCE__
@@ -1543,7 +1545,7 @@ bool wxLocale::Init(const wxChar *szName,
       256);
   if (ret != 0)
   {
-    m_pszOldLocale = wxStrdup(localeName);
+    m_pszOldLocale = wxStrdup(wxConvLibc.cWC2MB(localeName));
   }
   else
     m_pszOldLocale = NULL;
@@ -1551,7 +1553,7 @@ bool wxLocale::Init(const wxChar *szName,
   // TODO: how to find languageId
   // SetLocaleInfo(languageId, SORT_DEFAULT, localeName);
 #else
-  wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale);
+  const char *oldLocale = wxSetlocale(LC_ALL, szLocale);
   if ( oldLocale )
       m_pszOldLocale = wxStrdup(oldLocale);
   else
@@ -1566,10 +1568,10 @@ bool wxLocale::Init(const wxChar *szName,
   if ( m_strShort.empty() ) {
     // FIXME I don't know how these 2 letter abbreviations are formed,
     //       this wild guess is surely wrong
-    if ( szLocale && szLocale[0] )
+    if ( !szLocale.empty() )
     {
         m_strShort += (wxChar)wxTolower(szLocale[0]);
-        if ( szLocale[1] )
+        if ( szLocale.length() > 1 )
             m_strShort += (wxChar)wxTolower(szLocale[1]);
     }
   }
@@ -1585,7 +1587,7 @@ bool wxLocale::Init(const wxChar *szName,
     // an error if this does not exist
     if ( bOk )
     {
-      wxString port(wxPlatformInfo().GetPortIdName());
+      wxString port(wxPlatformInfo::Get().GetPortIdName());
       if ( !port.empty() )
       {
         AddCatalog(port.BeforeFirst(wxT('/')).MakeLower());
@@ -1598,35 +1600,44 @@ bool wxLocale::Init(const wxChar *szName,
 
 
 #if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__)
-static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc)
+static const char *wxSetlocaleTryUTF8(int c, const wxString& lc)
 {
-    wxMB2WXbuf l = wxSetlocale(c, lc);
-    if ( !l && lc && lc[0] != 0 )
+    const char *l = NULL;
+
+    // NB: We prefer to set UTF-8 locale if it's possible and only fall back to
+    //     non-UTF-8 locale if it fails
+
+    if ( !lc.empty() )
     {
         wxString buf(lc);
         wxString buf2;
         buf2 = buf + wxT(".UTF-8");
-        l = wxSetlocale(c, buf2.c_str());
+        l = wxSetlocale(c, buf2);
         if ( !l )
         {
             buf2 = buf + wxT(".utf-8");
-            l = wxSetlocale(c, buf2.c_str());
+            l = wxSetlocale(c, buf2);
         }
         if ( !l )
         {
             buf2 = buf + wxT(".UTF8");
-            l = wxSetlocale(c, buf2.c_str());
+            l = wxSetlocale(c, buf2);
         }
         if ( !l )
         {
             buf2 = buf + wxT(".utf8");
-            l = wxSetlocale(c, buf2.c_str());
+            l = wxSetlocale(c, buf2);
         }
     }
+
+    // if we can't set UTF-8 locale, try non-UTF-8 one:
+    if ( !l )
+        l = wxSetlocale(c, lc);
+
     return l;
 }
 #else
-#define wxSetlocaleTryUTF(c, lc)  wxSetlocale(c, lc)
+#define wxSetlocaleTryUTF8(c, lc)  wxSetlocale(c, lc)
 #endif
 
 bool wxLocale::Init(int language, int flags)
@@ -1659,18 +1670,18 @@ bool wxLocale::Init(int language, int flags)
 
     // Set the locale:
 #if defined(__OS2__)
-    wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString);
+    const char *retloc = wxSetlocale(LC_ALL , wxEmptyString);
 #elif defined(__UNIX__) && !defined(__WXMAC__)
     if (language != wxLANGUAGE_DEFAULT)
         locale = info->CanonicalName;
 
-    wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale);
+    const char *retloc = wxSetlocaleTryUTF8(LC_ALL, locale);
 
     const wxString langOnly = locale.Left(2);
     if ( !retloc )
     {
         // Some C libraries don't like xx_YY form and require xx only
-        retloc = wxSetlocaleTryUTF(LC_ALL, langOnly);
+        retloc = wxSetlocaleTryUTF8(LC_ALL, langOnly);
     }
 
 #if wxUSE_FONTMAP
@@ -1711,9 +1722,9 @@ bool wxLocale::Init(int language, int flags)
 
         if ( !localeAlt.empty() )
         {
-            retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt);
+            retloc = wxSetlocaleTryUTF8(LC_ALL, localeAlt);
             if ( !retloc )
-                retloc = wxSetlocaleTryUTF(LC_ALL, locale.Left(2));
+                retloc = wxSetlocaleTryUTF8(LC_ALL, localeAlt.Left(2));
         }
     }
 
@@ -1724,15 +1735,16 @@ bool wxLocale::Init(int language, int flags)
     }
 
 #ifdef __AIX__
-    // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL)
-    // can't be passed back to it because it returns 6 strings (one for each locale
-    // category), i.e. for C locale we get back "C C C C C C"
+    // at least in AIX 5.2 libc is buggy and the string returned from
+    // setlocale(LC_ALL) can't be passed back to it because it returns 6
+    // strings (one for each locale category), i.e. for C locale we get back
+    // "C C C C C C"
     //
-    // this contradicts IBM own docs but this is not of much help, so just work around
-    // it in the crudest possible manner
-    wxChar *p = wxStrchr((wxChar *)retloc, _T(' '));
+    // this contradicts IBM own docs but this is not of much help, so just work
+    // around it in the crudest possible manner
+    char *p = wxStrchr(retloc, ' ');
     if ( p )
-        *p = _T('\0');
+        *p = '\0';
 #endif // __AIX__
 
 #elif defined(__WIN32__)
@@ -1747,10 +1759,7 @@ bool wxLocale::Init(int language, int flags)
         #define SETLOCALE_FAILS_ON_UNICODE_LANGS
     #endif
 
-#if !wxUSE_UNICODE
-    const
-#endif
-    wxMB2WXbuf retloc = wxT("C");
+    const char *retloc = "C";
     if (language != wxLANGUAGE_DEFAULT)
     {
         if (info->WinLang == 0)
@@ -1799,9 +1808,9 @@ bool wxLocale::Init(int language, int flags)
                 retloc = wxSetlocale(LC_ALL, locale);
 #endif
 #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
-                if (codepage == 0 && (const wxChar*)retloc == NULL)
+                if (codepage == 0 && retloc == NULL)
                 {
-                    retloc = wxT("C");
+                    retloc = "C";
                 }
 #endif
             }
@@ -1816,14 +1825,14 @@ bool wxLocale::Init(int language, int flags)
         retloc = NULL;
 #endif
 #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
-        if ((const wxChar*)retloc == NULL)
+        if (retloc == NULL)
         {
             wxChar buffer[16];
             if (GetLocaleInfo(LOCALE_USER_DEFAULT,
                               LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 &&
                  wxStrcmp(buffer, wxT("0")) == 0)
             {
-                retloc = wxT("C");
+                retloc = "C";
             }
         }
 #endif
@@ -1840,7 +1849,7 @@ bool wxLocale::Init(int language, int flags)
     else
         locale = info->CanonicalName;
 
-    wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale);
+    const char *retloc = wxSetlocale(LC_ALL, locale);
 
     if ( !retloc )
     {
@@ -1859,11 +1868,9 @@ bool wxLocale::Init(int language, int flags)
 #endif
 
 #ifndef WX_NO_LOCALE_SUPPORT
-    wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL;
-    bool ret = Init(name, canonical, szLocale,
+    bool ret = Init(name, canonical, retloc,
                     (flags & wxLOCALE_LOAD_DEFAULT) != 0,
                     (flags & wxLOCALE_CONV_ENCODING) != 0);
-    free(szLocale);
 
     if (IsOk()) // setlocale() succeeded
         m_language = lang;
@@ -1898,14 +1905,14 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix)
         !wxGetEnv(wxT("LC_MESSAGES"), &langFull) &&
         !wxGetEnv(wxT("LANG"), &langFull))
     {
-        // no language specified, threat it as English
-        return wxLANGUAGE_ENGLISH;
+        // no language specified, treat it as English
+        return wxLANGUAGE_ENGLISH_US;
     }
 
     if ( langFull == _T("C") || langFull == _T("POSIX") )
     {
-        // default C locale
-        return wxLANGUAGE_ENGLISH;
+        // default C locale is English too
+        return wxLANGUAGE_ENGLISH_US;
     }
 
     // the language string has the following form
@@ -2466,7 +2473,13 @@ wxFontEncoding wxLocale::GetSystemEncoding()
         // (a.k.a. US-ASCII) which is arguably a bug but keep it like this for
         // backwards compatibility and just take care to not return
         // wxFONTENCODING_DEFAULT from here as this surely doesn't make sense
-        if ( enc != wxFONTENCODING_MAX && enc != wxFONTENCODING_DEFAULT )
+        if ( enc == wxFONTENCODING_DEFAULT )
+        {
+            // we don't have wxFONTENCODING_ASCII, so use the closest one
+            return wxFONTENCODING_ISO8859_1;
+        }
+
+        if ( enc != wxFONTENCODING_MAX )
         {
             return enc;
         }
@@ -2499,7 +2512,9 @@ const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang)
     {
         if ( ms_languagesDB->Item(i).Language == lang )
         {
-            return &ms_languagesDB->Item(i);
+            // We need to create a temporary here in order to make this work with BCC in final build mode
+            wxLanguageInfo *ptr = &ms_languagesDB->Item(i);
+            return ptr;
         }
     }
 
@@ -2542,7 +2557,7 @@ const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale)
             // looking
             //
             // OTOH, maybe we had already found a language match and in this
-            // case don't overwrite it becauce the entry for the default
+            // case don't overwrite it because the entry for the default
             // country always appears first in ms_languagesDB
             if ( !infoRet )
                 infoRet = info;
@@ -2584,43 +2599,43 @@ wxLocale::~wxLocale()
 }
 
 // get the translation of given string in current locale
-const wxChar *wxLocale::GetString(const wxChar *szOrigString,
-                                  const wxChar *szDomain) const
+const wxString& wxLocale::GetString(const wxString& origString,
+                                    const wxString& domain) const
 {
-    return GetString(szOrigString, szOrigString, size_t(-1), szDomain);
+    return GetString(origString, origString, size_t(-1), domain);
 }
 
-const wxChar *wxLocale::GetString(const wxChar *szOrigString,
-                                  const wxChar *szOrigString2,
-                                  size_t n,
-                                  const wxChar *szDomain) const
+const wxString& wxLocale::GetString(const wxString& origString,
+                                    const wxString& origString2,
+                                    size_t n,
+                                    const wxString& domain) const
 {
-    if ( wxIsEmpty(szOrigString) )
-        return wxEmptyString;
+    if ( origString.empty() )
+        return GetUntranslatedString(origString);
 
-    const wxChar *pszTrans = NULL;
+    const wxString *trans = NULL;
     wxMsgCatalog *pMsgCat;
 
-    if ( szDomain != NULL )
+    if ( !domain.empty() )
     {
-        pMsgCat = FindCatalog(szDomain);
+        pMsgCat = FindCatalog(domain);
 
         // does the catalog exist?
         if ( pMsgCat != NULL )
-            pszTrans = pMsgCat->GetString(szOrigString, n);
+            trans = pMsgCat->GetString(origString, n);
     }
     else
     {
         // search in all domains
         for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
         {
-            pszTrans = pMsgCat->GetString(szOrigString, n);
-            if ( pszTrans != NULL )   // take the first found
+            trans = pMsgCat->GetString(origString, n);
+            if ( trans != NULL )   // take the first found
                 break;
         }
     }
 
-    if ( pszTrans == NULL )
+    if ( trans == NULL )
     {
 #ifdef __WXDEBUG__
         if ( !NoTransErr::Suppress() )
@@ -2629,82 +2644,95 @@ const wxChar *wxLocale::GetString(const wxChar *szOrigString,
 
             wxLogTrace(TRACE_I18N,
                        _T("string \"%s\"[%ld] not found in %slocale '%s'."),
-                       szOrigString, (long)n,
-                       szDomain ? wxString::Format(_T("domain '%s' "), szDomain).c_str()
-                                : _T(""),
+                       origString, (long)n,
+                       domain.empty()
+                         ? (const wxChar*)wxString::Format(_T("domain '%s' "), domain).c_str()
+                         : _T(""),
                        m_strLocale.c_str());
         }
 #endif // __WXDEBUG__
 
         if (n == size_t(-1))
-            return szOrigString;
+            return GetUntranslatedString(origString);
         else
-            return n == 1 ? szOrigString : szOrigString2;
+            return GetUntranslatedString(n == 1 ? origString : origString2);
     }
 
-    return pszTrans;
+    return *trans;
+}
+
+WX_DECLARE_HASH_SET(wxString, wxStringHash, wxStringEqual,
+                    wxLocaleUntranslatedStrings);
+
+/* static */
+const wxString& wxLocale::GetUntranslatedString(const wxString& str)
+{
+    static wxLocaleUntranslatedStrings s_strings;
+
+    wxLocaleUntranslatedStrings::iterator i = s_strings.find(str);
+    if ( i == s_strings.end() )
+        return *s_strings.insert(str).first;
+
+    return *i;
 }
 
-wxString wxLocale::GetHeaderValue( const wxChar* szHeader,
-                                   const wxChar* szDomain ) const
+wxString wxLocale::GetHeaderValue(const wxString& header,
+                                  const wxString& domain) const
 {
-    if ( wxIsEmpty(szHeader) )
+    if ( header.empty() )
         return wxEmptyString;
 
-    wxChar const * pszTrans = NULL;
+    const wxString *trans = NULL;
     wxMsgCatalog *pMsgCat;
 
-    if ( szDomain != NULL )
+    if ( !domain.empty() )
     {
-        pMsgCat = FindCatalog(szDomain);
+        pMsgCat = FindCatalog(domain);
 
         // does the catalog exist?
         if ( pMsgCat == NULL )
             return wxEmptyString;
 
-        pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1);
+        trans = pMsgCat->GetString(wxEmptyString, (size_t)-1);
     }
     else
     {
         // search in all domains
         for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
         {
-            pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1);
-            if ( pszTrans != NULL )   // take the first found
+            trans = pMsgCat->GetString(wxEmptyString, (size_t)-1);
+            if ( trans != NULL )   // take the first found
                 break;
         }
     }
 
-    if ( wxIsEmpty(pszTrans) )
+    if ( !trans || trans->empty() )
       return wxEmptyString;
 
-    wxChar const * pszFound = wxStrstr(pszTrans, szHeader);
-    if ( pszFound == NULL )
+    size_t found = trans->find(header);
+    if ( found == wxString::npos )
       return wxEmptyString;
 
-    pszFound += wxStrlen(szHeader) + 2 /* ': ' */;
+    found += header.length() + 2 /* ': ' */;
 
     // Every header is separated by \n
 
-    wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n'));
-    if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound);
-
+    size_t endLine = trans->find(wxT('\n'), found);
+    size_t len = (endLine == wxString::npos) ?
+                 wxString::npos : (endLine - found);
 
-    // wxString( wxChar*, length);
-    wxString retVal( pszFound, pszEndLine - pszFound );
-
-    return retVal;
+    return trans->substr(found, len);
 }
 
 
 // find catalog by name in a linked list, return NULL if !found
-wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const
+wxMsgCatalog *wxLocale::FindCatalog(const wxString& domain) const
 {
     // linear search in the linked list
     wxMsgCatalog *pMsgCat;
     for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
     {
-        if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 )
+        if ( pMsgCat->GetName() == domain )
           return pMsgCat;
     }
 
@@ -2718,7 +2746,7 @@ bool wxLocale::IsAvailable(int lang)
     const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang);
     wxCHECK_MSG( info, false, _T("invalid language") );
 
-#ifdef __WIN32__
+#if defined(__WIN32__)
     if ( !info->WinLang )
         return false;
 
@@ -2728,30 +2756,43 @@ bool wxLocale::IsAvailable(int lang)
                          SORT_DEFAULT),
                 LCID_INSTALLED
             ) )
-      return false;
-#else // !__WIN32__
-    // TODO: test if setlocale(info->CanonicalName) works under other OS?
-#endif // __WIN32__/!__WIN32__
+        return false;
+
+#elif defined(__UNIX__)
+
+    // Test if setting the locale works, then set it back.
+    const char *oldLocale = wxSetlocale(LC_ALL, "");
+    const char *tmp = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName);
+    if ( !tmp )
+    {
+        // Some C libraries don't like xx_YY form and require xx only
+        tmp = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName.Left(2));
+        if ( !tmp )
+            return false;
+    }
+    // restore the original locale
+    wxSetlocale(LC_ALL, oldLocale);
+#endif
 
     return true;
 }
 
 // check if the given catalog is loaded
-bool wxLocale::IsLoaded(const wxChar *szDomain) const
+bool wxLocale::IsLoaded(const wxString& szDomain) const
 {
   return FindCatalog(szDomain) != NULL;
 }
 
 // add a catalog to our linked list
-bool wxLocale::AddCatalog(const wxChar *szDomain)
+bool wxLocale::AddCatalog(const wxString& szDomain)
 {
-    return AddCatalog(szDomain, wxLANGUAGE_ENGLISH, NULL);
+    return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, wxEmptyString);
 }
 
 // add a catalog to our linked list
-bool wxLocale::AddCatalog(const wxChar *szDomain,
-                          wxLanguage    msgIdLanguage,
-                          const wxChar *msgIdCharset)
+bool wxLocale::AddCatalog(const wxString& szDomain,
+                          wxLanguage      msgIdLanguage,
+                          const wxString& msgIdCharset)
 
 {
   wxMsgCatalog *pMsgCat = new wxMsgCatalog;