X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c9f7896861f734ce044ee8601ba2d8a6959c9d9e..69659fd770f615210efac4b4fa741b3ad6223616:/src/common/intl.cpp diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 40c997970f..0a027c9971 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -69,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 @@ -872,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 @@ -962,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; @@ -1014,7 +1015,7 @@ wxMsgCatalogFile::~wxMsgCatalogFile() // return the directories to search for message catalogs under the given // prefix, separated by wxPATH_SEP static -wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang) +wxString GetMsgCatalogSubdirs(const wxString& prefix, const wxString& lang) { wxString searchPath; searchPath << prefix << wxFILE_SEP_PATH << lang; @@ -1036,7 +1037,7 @@ wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang) } // 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; @@ -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]); } } @@ -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, localeAlt.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; @@ -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; } @@ -2544,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; @@ -2586,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() ) @@ -2631,83 +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 - ? (const wxChar*)wxString::Format(_T("domain '%s' "), szDomain).c_str() + 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); - - - // wxString( wxChar*, length); - wxString retVal( pszFound, pszEndLine - pszFound ); + size_t endLine = trans->find(wxT('\n'), found); + size_t len = (endLine == wxString::npos) ? + wxString::npos : (endLine - found); - 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; } @@ -2734,40 +2759,40 @@ bool wxLocale::IsAvailable(int lang) return false; #elif defined(__UNIX__) - - // Test if setting the locale works, then set it back. - wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); - wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); + + // 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 = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2)); + tmp = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName.Left(2)); if ( !tmp ) return false; } // restore the original locale - wxSetlocale(LC_ALL, oldLocale); -#endif + 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_US, 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;