X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b2fde0cfedc01146bbfd249e97243ced65e319dd..fc32630a5e03e60a67d4ef53fc59985ea087b451:/src/common/intl.cpp?ds=sidebyside diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 95eb80b3e1..8d0f5f9891 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -18,12 +18,6 @@ // headers // ---------------------------------------------------------------------------- -#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" @@ -31,6 +25,12 @@ #pragma hdrstop #endif +#ifdef __EMX__ +// The following define is needed by Innotek's libc to +// make the definition of struct localeconv available. +#define __INTERNAL_DEFS +#endif + #if wxUSE_INTL #ifndef WX_PRECOMP @@ -69,9 +69,13 @@ #include "wx/ptr_scpd.h" #include "wx/apptrait.h" #include "wx/stdpaths.h" +#include "wx/hashset.h" +#include "wx/filesys.h" -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers +#if defined(__DARWIN__) + #include "wx/mac/corefoundation/cfref.h" + #include + #include "wx/mac/corefoundation/cfstring.h" #endif // ---------------------------------------------------------------------------- @@ -95,7 +99,7 @@ static const size_t LEN_LANG = 2; static const size_t LEN_SUBLANG = 2; static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_' -#define TRACE_I18N _T("i18n") +#define TRACE_I18N wxS("i18n") // ---------------------------------------------------------------------------- // global functions @@ -232,7 +236,7 @@ wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s) bool wxPluralFormsScanner::nextToken() { wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR; - while (isspace(*m_s)) + while (isspace((unsigned char) *m_s)) { ++m_s; } @@ -240,20 +244,20 @@ bool wxPluralFormsScanner::nextToken() { type = wxPluralFormsToken::T_EOF; } - else if (isdigit(*m_s)) + else if (isdigit((unsigned char) *m_s)) { wxPluralFormsToken::Number number = *m_s++ - '0'; - while (isdigit(*m_s)) + while (isdigit((unsigned char) *m_s)) { number = number * 10 + (*m_s++ - '0'); } m_token.setNumber(number); type = wxPluralFormsToken::T_NUMBER; } - else if (isalpha(*m_s)) + else if (isalpha((unsigned char) *m_s)) { const char* begin = m_s++; - while (isalnum(*m_s)) + while (isalnum((unsigned char) *m_s)) { ++m_s; } @@ -872,7 +876,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 @@ -906,11 +910,8 @@ private: ofsHashTable; // +18: offset of hash table start }; - // all data is stored here, NULL if no data loaded - size_t8 *m_pData; - - // amount of memory pointed to by m_pData. - size_t32 m_nSize; + // all data is stored here + wxMemoryBuffer m_data; // data description size_t32 m_numStrings; // number of strings in this domain @@ -928,18 +929,25 @@ private: : ui; } + // just return the pointer to the start of the data as "char *" to + // facilitate doing pointer arithmetic with it + char *StringData() const + { + return wx_static_cast(char *, m_data.GetData()); + } + const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const { const wxMsgTableEntry * const ent = pTable + n; // this check could fail for a corrupt message catalog size_t32 ofsString = Swap(ent->ofsString); - if ( ofsString + Swap(ent->nLen) > m_nSize) + if ( ofsString + Swap(ent->nLen) > m_data.GetDataLen()) { return NULL; } - return (const char *)(m_pData + ofsString); + return StringData() + ofsString; } bool m_bSwapped; // wrong endianness? @@ -958,18 +966,20 @@ private: class wxMsgCatalog { public: +#if !wxUSE_UNICODE wxMsgCatalog() { m_conv = NULL; } ~wxMsgCatalog(); +#endif // 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; @@ -978,9 +988,11 @@ private: wxMessagesHash m_messages; // all messages in the catalog wxString m_name; // name of the domain +#if !wxUSE_UNICODE // the conversion corresponding to this catalog charset if we installed it // as the global one wxCSConv *m_conv; +#endif wxPluralFormsCalculatorPtr m_pluralFormsCalculator; }; @@ -996,47 +1008,109 @@ static wxArrayString gs_searchPrefixes; // implementation // ============================================================================ +// ---------------------------------------------------------------------------- +// wxLanguageInfo +// ---------------------------------------------------------------------------- + +#ifdef __WXMSW__ + +// helper used by wxLanguageInfo::GetLocaleName() and elsewhere to determine +// whether the locale is Unicode-only (it is if this function returns empty +// string) +static wxString wxGetANSICodePageForLocale(LCID lcid) +{ + wxString cp; + + wxChar buffer[16]; + if ( ::GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, + buffer, WXSIZEOF(buffer)) > 0 ) + { + if ( buffer[0] != _T('0') || buffer[1] != _T('\0') ) + cp = buffer; + //else: this locale doesn't use ANSI code page + } + + return cp; +} + +wxUint32 wxLanguageInfo::GetLCID() const +{ + return MAKELCID(MAKELANGID(WinLang, WinSublang), SORT_DEFAULT); +} + +wxString wxLanguageInfo::GetLocaleName() const +{ + wxString locale; + + const LCID lcid = GetLCID(); + + wxChar buffer[256]; + buffer[0] = _T('\0'); + if ( !::GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, WXSIZEOF(buffer)) ) + { + wxLogLastError(_T("GetLocaleInfo(LOCALE_SENGLANGUAGE)")); + return locale; + } + + locale << buffer; + if ( ::GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, + buffer, WXSIZEOF(buffer)) > 0 ) + { + locale << _T('_') << buffer; + } + + const wxString cp = wxGetANSICodePageForLocale(lcid); + if ( !cp.empty() ) + { + locale << _T('.') << cp; + } + + return locale; +} + +#endif // __WXMSW__ + // ---------------------------------------------------------------------------- // wxMsgCatalogFile class // ---------------------------------------------------------------------------- wxMsgCatalogFile::wxMsgCatalogFile() { - m_pData = NULL; - m_nSize = 0; } wxMsgCatalogFile::~wxMsgCatalogFile() { - delete [] m_pData; } // 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; - - // 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: + // Search first in Unix-standard prefix/lang/LC_MESSAGES, then in + // prefix/lang and finally in just prefix. + // + // Note that we use LC_MESSAGES 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; + const wxString pathPrefix = wxFileName(prefix, lang).GetFullPath(); + + wxString searchPath; + searchPath.reserve(4*pathPrefix.length()); + searchPath << pathPrefix << wxFILE_SEP_PATH << "LC_MESSAGES" << wxPATH_SEP + << prefix << wxFILE_SEP_PATH << wxPATH_SEP + << pathPrefix; 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; @@ -1062,7 +1136,7 @@ static wxString GetFullSearchPath(const wxChar *lang) #ifdef __UNIX__ // LC_PATH is a standard env var containing the search path for the .mo // files - const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); + const char *pszLcPath = wxGetenv("LC_PATH"); if ( pszLcPath ) { const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); @@ -1074,7 +1148,7 @@ static wxString GetFullSearchPath(const wxChar *lang) wxString wxp = wxGetInstallPrefix(); if ( !wxp.empty() ) { - wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang); + wxp = GetMsgCatalogSubdirs(wxp + wxS("/share/locale"), lang); if ( paths.Index(wxp) == wxNOT_FOUND ) paths.Add(wxp); } @@ -1096,7 +1170,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; @@ -1110,22 +1184,21 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, if ( encSys != wxFONTENCODING_SYSTEM ) { wxString fullname(szDirPrefix); - fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys); + fullname << wxS('.') << wxFontMapperBase::GetEncodingName(encSys); searchPath << GetFullSearchPath(fullname) << wxPATH_SEP; } #endif // wxUSE_FONTMAP searchPath += GetFullSearchPath(szDirPrefix); - const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_')); - if ( sublocale ) + size_t sublocaleIndex = szDirPrefix.find(wxS('_')); + 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 @@ -1136,22 +1209,45 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, NoTransErr noTransErr; wxLogVerbose(_("looking for catalog '%s' in path '%s'."), szName, searchPath.c_str()); - wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""), + wxLogTrace(TRACE_I18N, wxS("Looking for \"%s.mo\" in \"%s\""), szName, searchPath.c_str()); wxFileName fn(szName); - fn.SetExt(_T("mo")); + fn.SetExt(wxS("mo")); + wxString strFullName; - if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) { +#if wxUSE_FILESYSTEM + wxFileSystem fileSys; + if ( !fileSys.FindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) +#else // !wxUSE_FILESYSTEM + if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) +#endif // wxUSE_FILESYSTEM/!wxUSE_FILESYSTEM + { wxLogVerbose(_("catalog file for domain '%s' not found."), szName); - wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName); + wxLogTrace(TRACE_I18N, wxS("Catalog \"%s.mo\" not found"), szName); return false; } - // open file + // open file and read its data wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str()); - wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str()); + wxLogTrace(TRACE_I18N, wxS("Using catalog \"%s\"."), strFullName.c_str()); + +#if wxUSE_FILESYSTEM + wxFSFile * const fileMsg = fileSys.OpenFile(strFullName); + if ( !fileMsg ) + return false; + + wxInputStream *fileStream = fileMsg->GetStream(); + m_data.SetDataLen(0); + static const size_t chunkSize = 4096; + while ( !fileStream->Eof() ) { + fileStream->Read(m_data.GetAppendBuf(chunkSize), chunkSize); + m_data.UngetAppendBuf(fileStream->LastRead()); + } + + delete fileMsg; +#else // !wxUSE_FILESYSTEM wxFile fileMsg(strFullName); if ( !fileMsg.IsOpened() ) return false; @@ -1162,19 +1258,18 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, return false; size_t nSize = wx_truncate_cast(size_t, lenFile); - wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") ); + wxASSERT_MSG( nSize == lenFile + size_t(0), wxS("message catalog bigger than 4GB?") ); // read the whole file in memory - m_pData = new size_t8[nSize]; - if ( fileMsg.Read(m_pData, nSize) != lenFile ) { - wxDELETEA(m_pData); + if ( fileMsg.Read(m_data.GetWriteBuf(nSize), nSize) != lenFile ) return false; - } +#endif // wxUSE_FILESYSTEM/!wxUSE_FILESYSTEM + // examine header - bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader); + bool bValid = m_data.GetDataLen() > sizeof(wxMsgCatalogHeader); - wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData; + const wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_data.GetData(); if ( bValid ) { // we'll have to swap all the integers if it's true m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW; @@ -1187,17 +1282,15 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, // it's either too short or has incorrect magic number wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str()); - wxDELETEA(m_pData); return false; } // initialize m_numStrings = Swap(pHeader->numStrings); - m_pOrigTable = (wxMsgTableEntry *)(m_pData + + m_pOrigTable = (wxMsgTableEntry *)(StringData() + Swap(pHeader->ofsOrigTable)); - m_pTransTable = (wxMsgTableEntry *)(m_pData + + m_pTransTable = (wxMsgTableEntry *)(StringData() + Swap(pHeader->ofsTransTable)); - m_nSize = (size_t32)nSize; // now parse catalog's header and try to extract catalog charset and // plural forms formula from it: @@ -1207,7 +1300,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, { // Extract the charset: wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0)); - int begin = header.Find(wxT("Content-Type: text/plain; charset=")); + int begin = header.Find(wxS("Content-Type: text/plain; charset=")); if (begin != wxNOT_FOUND) { begin += 34; //strlen("Content-Type: text/plain; charset=") @@ -1215,7 +1308,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, if (end != size_t(-1)) { m_charset.assign(header, begin, end - begin); - if (m_charset == wxT("CHARSET")) + if (m_charset == wxS("CHARSET")) { // "CHARSET" is not valid charset, but lazy translator m_charset.Clear(); @@ -1225,7 +1318,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, // else: incorrectly filled Content-Type header // Extract plural forms: - begin = header.Find(wxT("Plural-Forms:")); + begin = header.Find(wxS("Plural-Forms:")); if (begin != wxNOT_FOUND) { begin += 13; @@ -1304,8 +1397,8 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, : new wxCSConv(msgIdCharset); #elif wxUSE_FONTMAP - wxASSERT_MSG( msgIdCharset == NULL, - _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); + wxASSERT_MSG( msgIdCharset.empty(), + wxS("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); wxEncodingConverter converter; if ( convertEncoding ) @@ -1374,7 +1467,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 @@ -1403,6 +1496,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, // wxMsgCatalog class // ---------------------------------------------------------------------------- +#if !wxUSE_UNICODE wxMsgCatalog::~wxMsgCatalog() { if ( m_conv ) @@ -1417,19 +1511,21 @@ wxMsgCatalog::~wxMsgCatalog() delete m_conv; } } +#endif // !wxUSE_UNICODE -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); +#if !wxUSE_UNICODE // we should use a conversion compatible with the message catalog encoding // in the GUI if we don't convert the strings to the current conversion but // as the encoding is global, only change it once, otherwise we could get @@ -1445,11 +1541,12 @@ bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, wxConvUI = m_conv = new wxCSConv(file.GetCharset()); } +#endif // !wxUSE_UNICODE 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 +1556,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,51 +1609,37 @@ 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") ); + wxS("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; - - wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") ); - } + szLocale = shortName; -#ifdef __WXWINCE__ - // FIXME: I'm guessing here - wxChar localeName[256]; - int ret = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLANGUAGE, localeName, - 256); - if (ret != 0) - { - m_pszOldLocale = wxStrdup(localeName); + wxCHECK_MSG( !szLocale.empty(), false, + wxS("no locale to set in wxLocale::Init()") ); } - else - m_pszOldLocale = NULL; - // 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 m_pszOldLocale = NULL; -#endif if ( m_pszOldLocale == NULL ) wxLogError(_("locale '%s' can not be set."), szLocale); @@ -1566,10 +1649,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]); } } @@ -1579,7 +1662,7 @@ bool wxLocale::Init(const wxChar *szName, bool bOk = true; if ( bLoadDefault ) { - bOk = AddCatalog(wxT("wxstd")); + bOk = AddCatalog(wxS("wxstd")); // there may be a catalog with toolkit specific overrides, it is not // an error if this does not exist @@ -1588,7 +1671,7 @@ bool wxLocale::Init(const wxChar *szName, wxString port(wxPlatformInfo::Get().GetPortIdName()); if ( !port.empty() ) { - AddCatalog(port.BeforeFirst(wxT('/')).MakeLower()); + AddCatalog(port.BeforeFirst(wxS('/')).MakeLower()); } } } @@ -1598,39 +1681,50 @@ 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()); + buf2 = buf + wxS(".UTF-8"); + l = wxSetlocale(c, buf2); if ( !l ) { - buf2 = buf + wxT(".utf-8"); - l = wxSetlocale(c, buf2.c_str()); + buf2 = buf + wxS(".utf-8"); + l = wxSetlocale(c, buf2); } if ( !l ) { - buf2 = buf + wxT(".UTF8"); - l = wxSetlocale(c, buf2.c_str()); + buf2 = buf + wxS(".UTF8"); + l = wxSetlocale(c, buf2); } if ( !l ) { - buf2 = buf + wxT(".utf8"); - l = wxSetlocale(c, buf2.c_str()); + buf2 = buf + wxS(".utf8"); + 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) { + bool ret = true; + int lang = language; if (lang == wxLANGUAGE_DEFAULT) { @@ -1649,7 +1743,7 @@ bool wxLocale::Init(int language, int flags) // Unknown language: if (info == NULL) { - wxLogError(wxT("Unknown language %i."), lang); + wxLogError(wxS("Unknown language %i."), lang); return false; } @@ -1659,18 +1753,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 @@ -1686,7 +1780,7 @@ bool wxLocale::Init(int language, int flags) wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); while ( *names ) { - retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++); + retloc = wxSetlocale(LC_ALL, locale + wxS('.') + *names++); if ( retloc ) break; } @@ -1698,160 +1792,109 @@ bool wxLocale::Init(int language, int flags) // Some C libraries (namely glibc) still use old ISO 639, // so will translate the abbrev for them wxString localeAlt; - if ( langOnly == wxT("he") ) - localeAlt = wxT("iw") + locale.Mid(3); - else if ( langOnly == wxT("id") ) - localeAlt = wxT("in") + locale.Mid(3); - else if ( langOnly == wxT("yi") ) - localeAlt = wxT("ji") + locale.Mid(3); - else if ( langOnly == wxT("nb") ) - localeAlt = wxT("no_NO"); - else if ( langOnly == wxT("nn") ) - localeAlt = wxT("no_NY"); + if ( langOnly == wxS("he") ) + localeAlt = wxS("iw") + locale.Mid(3); + else if ( langOnly == wxS("id") ) + localeAlt = wxS("in") + locale.Mid(3); + else if ( langOnly == wxS("yi") ) + localeAlt = wxS("ji") + locale.Mid(3); + else if ( langOnly == wxS("nb") ) + localeAlt = wxS("no_NO"); + else if ( langOnly == wxS("nn") ) + localeAlt = wxS("no_NY"); 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)); } } if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); - return false; - } + ret = false; #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 = const_cast(wxStrchr(retloc, ' ')); if ( p ) - *p = _T('\0'); + *p = '\0'; #endif // __AIX__ #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 - -#if !wxUSE_UNICODE - const -#endif - wxMB2WXbuf retloc = wxT("C"); - if (language != wxLANGUAGE_DEFAULT) + const char *retloc = "C"; + if ( language != wxLANGUAGE_DEFAULT ) { - if (info->WinLang == 0) + if ( info->WinLang == 0 ) { - wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str()); + wxLogWarning(wxS("Locale '%s' not supported by OS."), name.c_str()); // retloc already set to "C" } - else + else // language supported by Windows { - int codepage - #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - = -1 - #endif - ; - wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT); - // FIXME + // Windows CE doesn't have SetThreadLocale() and there doesn't seem + // to be any equivalent #ifndef __WXWINCE__ - SetThreadLocale(lcid); -#endif - // 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.empty()) + const wxUint32 lcid = info->GetLCID(); + + // change locale used by Windows functions + ::SetThreadLocale(lcid); +#endif + + // and also call setlocale() to change locale used by the CRT + locale = info->GetLocaleName(); + if ( locale.empty() ) { - wxLogLastError(wxT("SetThreadLocale")); - wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); - return false; + ret = false; } - else + else // have a valid locale { - // FIXME -#ifndef __WXWINCE__ retloc = wxSetlocale(LC_ALL, locale); -#endif -#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - if (codepage == 0 && (const wxChar*)retloc == NULL) - { - retloc = wxT("C"); - } -#endif } } } - else + else // language == wxLANGUAGE_DEFAULT { - // FIXME -#ifndef __WXWINCE__ retloc = wxSetlocale(LC_ALL, wxEmptyString); -#else - retloc = NULL; -#endif -#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 wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) + // VC++ setlocale() (also used by Mingw) can't set locale to languages that + // can only be written using Unicode, therefore wxSetlocale() call fails + // for such languages but we don't want to report it as an error -- so that + // at least message catalogs can be used. if ( !retloc ) { - wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); - return false; + if ( wxGetANSICodePageForLocale(LOCALE_USER_DEFAULT).empty() ) + { + // we set the locale to a Unicode-only language, don't treat the + // inability of CRT to use it as an error + retloc = "C"; + } } +#endif // CRT not handling Unicode-only languages + + if ( !retloc ) + ret = false; #elif defined(__WXMAC__) if (lang == wxLANGUAGE_DEFAULT) locale = wxEmptyString; else locale = info->CanonicalName; - wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale); + const char *retloc = wxSetlocale(LC_ALL, locale); 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 ) - { - wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); - return false; - } #else wxUnusedVar(flags); return false; @@ -1859,11 +1902,20 @@ 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, - (flags & wxLOCALE_LOAD_DEFAULT) != 0, - (flags & wxLOCALE_CONV_ENCODING) != 0); - free(szLocale); + if ( !ret ) + { + wxLogWarning(_("Cannot set locale to language \"%s\"."), name.c_str()); + + // continue nevertheless and try to load at least the translations for + // this language + } + + if ( !Init(name, canonical, retloc, + (flags & wxLOCALE_LOAD_DEFAULT) != 0, + (flags & wxLOCALE_CONV_ENCODING) != 0) ) + { + ret = false; + } if (IsOk()) // setlocale() succeeded m_language = lang; @@ -1891,22 +1943,34 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) size_t i = 0, count = ms_languagesDB->GetCount(); -#if defined(__UNIX__) && !defined(__WXMAC__) +#if defined(__UNIX__) // first get the string identifying the language from the environment wxString langFull; - if (!wxGetEnv(wxT("LC_ALL"), &langFull) && - !wxGetEnv(wxT("LC_MESSAGES"), &langFull) && - !wxGetEnv(wxT("LANG"), &langFull)) +#ifdef __WXMAC__ + wxCFRef userLocaleRef(CFLocaleCopyCurrent()); + + // because the locale identifier (kCFLocaleIdentifier) is formatted a little bit differently, eg + // az_Cyrl_AZ@calendar=buddhist;currency=JPY we just recreate the base info as expected by wx here + + wxCFStringRef str(wxCFRetain((CFStringRef)CFLocaleGetValue(userLocaleRef, kCFLocaleLanguageCode))); + langFull = str.AsString()+"_"; + str.reset(wxCFRetain((CFStringRef)CFLocaleGetValue(userLocaleRef, kCFLocaleCountryCode))); + langFull += str.AsString(); +#else + if (!wxGetEnv(wxS("LC_ALL"), &langFull) && + !wxGetEnv(wxS("LC_MESSAGES"), &langFull) && + !wxGetEnv(wxS("LANG"), &langFull)) { // no language specified, treat it as English return wxLANGUAGE_ENGLISH_US; } - if ( langFull == _T("C") || langFull == _T("POSIX") ) + if ( langFull == wxS("C") || langFull == wxS("POSIX") ) { // default C locale is English too return wxLANGUAGE_ENGLISH_US; } +#endif // the language string has the following form // @@ -1928,9 +1992,14 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) // for now we don't use the encoding, although we probably should (doing // translations of the msg catalogs on the fly as required) (TODO) // - // we don't use the modifiers neither but we probably should translate - // "euro" into iso885915 - size_t posEndLang = langFull.find_first_of(_T("@.")); + // we need the modified for languages like Valencian: ca_ES@valencia + // though, remember it + wxString modifier; + size_t posModifier = langFull.find_first_of(wxS("@")); + if ( posModifier != wxString::npos ) + modifier = langFull.Mid(posModifier); + + size_t posEndLang = langFull.find_first_of(wxS("@.")); if ( posEndLang != wxString::npos ) { langFull.Truncate(posEndLang); @@ -1943,7 +2012,7 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) // do we have just the language (or sublang too)? bool justLang = langFull.length() == LEN_LANG; if ( justLang || - (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT('_')) ) + (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxS('_')) ) { // 0. Make sure the lang is according to latest ISO 639 // (this is necessary because glibc uses iw and in instead @@ -1953,18 +2022,18 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) wxString langOrig = ExtractLang(langFull); wxString lang; - if ( langOrig == wxT("iw")) - lang = _T("he"); - else if (langOrig == wxT("in")) - lang = wxT("id"); - 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"); + if ( langOrig == wxS("iw")) + lang = wxS("he"); + else if (langOrig == wxS("in")) + lang = wxS("id"); + else if (langOrig == wxS("ji")) + lang = wxS("yi"); + else if (langOrig == wxS("no_NO")) + lang = wxS("nb_NO"); + else if (langOrig == wxS("no_NY")) + lang = wxS("nn_NO"); + else if (langOrig == wxS("no")) + lang = wxS("nb_NO"); else lang = langOrig; @@ -1975,11 +2044,24 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) } // 1. Try to find the language either as is: - for ( i = 0; i < count; i++ ) + // a) With modifier if set + if ( !modifier.empty() ) { - if ( ms_languagesDB->Item(i).CanonicalName == langFull ) + wxString langFullWithModifier = langFull + modifier; + for ( i = 0; i < count; i++ ) { - break; + if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) + break; + } + } + + // b) Without modifier + if ( modifier.empty() || i == count ) + { + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == langFull ) + break; } } @@ -2019,292 +2101,6 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) } } } -#elif defined(__WXMAC__) - const wxChar * lc = NULL ; - long lang = GetScriptVariable( smSystemScript, smScriptLang) ; - switch( GetScriptManagerVariable( smRegionCode ) ) { - case verUS : - lc = wxT("en_US") ; - break ; - case verFrance : - lc = wxT("fr_FR") ; - break ; - case verBritain : - lc = wxT("en_GB") ; - break ; - case verGermany : - lc = wxT("de_DE") ; - break ; - case verItaly : - lc = wxT("it_IT") ; - break ; - case verNetherlands : - lc = wxT("nl_NL") ; - break ; - case verFlemish : - lc = wxT("nl_BE") ; - break ; - case verSweden : - lc = wxT("sv_SE" ); - break ; - case verSpain : - lc = wxT("es_ES" ); - break ; - case verDenmark : - lc = wxT("da_DK") ; - break ; - case verPortugal : - lc = wxT("pt_PT") ; - break ; - case verFrCanada: - lc = wxT("fr_CA") ; - break ; - case verNorway: - lc = wxT("nb_NO") ; - break ; - case verIsrael: - lc = wxT("iw_IL") ; - break ; - case verJapan: - lc = wxT("ja_JP") ; - break ; - case verAustralia: - lc = wxT("en_AU") ; - break ; - case verArabic: - lc = wxT("ar") ; - break ; - case verFinland: - lc = wxT("fi_FI") ; - break ; - case verFrSwiss: - lc = wxT("fr_CH") ; - break ; - case verGrSwiss: - lc = wxT("de_CH") ; - break ; - case verGreece: - lc = wxT("el_GR") ; - break ; - case verIceland: - lc = wxT("is_IS") ; - break ; - case verMalta: - 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 = wxT("el_GR") ; - } - else if ( lang == langTurkish ) { - lc = wxT("tr_TR") ; - } - break ; - case verTurkey: - lc = wxT("tr_TR") ; - break ; - case verYugoCroatian: - lc = wxT("hr_HR") ; - break ; - case verIndiaHindi: - lc = wxT("hi_IN") ; - break ; - case verPakistanUrdu: - lc = wxT("ur_PK") ; - break ; - case verTurkishModified: - lc = wxT("tr_TR") ; - break ; - case verItalianSwiss: - lc = wxT("it_CH") ; - break ; - case verInternational: - lc = wxT("en") ; - break ; - case verRomania: - lc = wxT("ro_RO") ; - break ; - case verGreecePoly: - lc = wxT("el_GR") ; - break ; - case verLithuania: - lc = wxT("lt_LT") ; - break ; - case verPoland: - lc = wxT("pl_PL") ; - break ; - case verMagyar : - case verHungary: - lc = wxT("hu_HU") ; - break ; - case verEstonia: - lc = wxT("et_EE") ; - break ; - case verLatvia: - lc = wxT("lv_LV") ; - break ; - case verSami: - // not known - break ; - case verFaroeIsl: - lc = wxT("fo_FO") ; - break ; - case verIran: - lc = wxT("fa_IR") ; - break ; - case verRussia: - lc = wxT("ru_RU") ; - break ; - case verIreland: - lc = wxT("ga_IE") ; - break ; - case verKorea: - lc = wxT("ko_KR") ; - break ; - case verChina: - lc = wxT("zh_CN") ; - break ; - case verTaiwan: - lc = wxT("zh_TW") ; - break ; - case verThailand: - lc = wxT("th_TH") ; - break ; - case verCzech: - lc = wxT("cs_CZ") ; - break ; - case verSlovak: - lc = wxT("sk_SK") ; - break ; - case verBengali: - lc = wxT("bn") ; - break ; - case verByeloRussian: - lc = wxT("be_BY") ; - break ; - case verUkraine: - lc = wxT("uk_UA") ; - break ; - case verGreeceAlt: - lc = wxT("el_GR") ; - break ; - case verSerbian: - lc = wxT("sr_YU") ; - break ; - case verSlovenian: - lc = wxT("sl_SI") ; - break ; - case verMacedonian: - lc = wxT("mk_MK") ; - break ; - case verCroatia: - lc = wxT("hr_HR") ; - break ; - case verBrazil: - lc = wxT("pt_BR ") ; - break ; - case verBulgaria: - lc = wxT("bg_BG") ; - break ; - case verCatalonia: - lc = wxT("ca_ES") ; - break ; - case verScottishGaelic: - lc = wxT("gd") ; - break ; - case verManxGaelic: - lc = wxT("gv") ; - break ; - case verBreton: - lc = wxT("br") ; - break ; - case verNunavut: - lc = wxT("iu_CA") ; - break ; - case verWelsh: - lc = wxT("cy") ; - break ; - case verIrishGaelicScript: - lc = wxT("ga_IE") ; - break ; - case verEngCanada: - lc = wxT("en_CA") ; - break ; - case verBhutan: - lc = wxT("dz_BT") ; - break ; - case verArmenian: - lc = wxT("hy_AM") ; - break ; - case verGeorgian: - lc = wxT("ka_GE") ; - break ; - case verSpLatinAmerica: - lc = wxT("es_AR") ; - break ; - case verTonga: - lc = wxT("to_TO" ); - break ; - case verFrenchUniversal: - lc = wxT("fr_FR") ; - break ; - case verAustria: - lc = wxT("de_AT") ; - break ; - case verGujarati: - lc = wxT("gu_IN") ; - break ; - case verPunjabi: - lc = wxT("pa") ; - break ; - case verIndiaUrdu: - lc = wxT("ur_IN") ; - break ; - case verVietnam: - lc = wxT("vi_VN") ; - break ; - case verFrBelgium: - lc = wxT("fr_BE") ; - break ; - case verUzbek: - lc = wxT("uz_UZ") ; - break ; - case verSingapore: - lc = wxT("zh_SG") ; - break ; - case verNynorsk: - lc = wxT("nn_NO") ; - break ; - case verAfrikaans: - lc = wxT("af_ZA") ; - break ; - case verEsperanto: - lc = wxT("eo") ; - break ; - case verMarathi: - lc = wxT("mr_IN") ; - break ; - case verTibetan: - lc = wxT("bo") ; - break ; - case verNepal: - lc = wxT("ne_NP") ; - break ; - case verGreenland: - lc = wxT("kl_GL") ; - break ; - default : - break ; - } - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == lc ) - { - break; - } - } - #elif defined(__WIN32__) LCID lcid = GetUserDefaultLCID(); if ( lcid != 0 ) @@ -2350,7 +2146,7 @@ wxString wxLocale::GetSystemEncodingName() #if defined(__WIN32__) && !defined(__WXMICROWIN__) // FIXME: what is the error return value for GetACP()? UINT codepage = ::GetACP(); - encname.Printf(_T("windows-%u"), codepage); + encname.Printf(wxS("windows-%u"), codepage); #elif defined(__WXMAC__) // default is just empty string, this resolves to the default system // encoding later @@ -2437,12 +2233,8 @@ wxFontEncoding wxLocale::GetSystemEncoding() return wxFONTENCODING_CP950; } #elif defined(__WXMAC__) - TextEncoding encoding = 0 ; -#if TARGET_CARBON + CFStringEncoding encoding = 0 ; encoding = CFStringGetSystemEncoding() ; -#else - UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ; -#endif return wxMacGetFontEncFromSystemEnc( encoding ) ; #elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP const wxString encname = GetSystemEncodingName(); @@ -2466,7 +2258,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; } @@ -2538,13 +2336,13 @@ const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale) break; } - if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 ) + if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(wxS('_'))) == 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 + // case don't overwrite it because the entry for the default // country always appears first in ms_languagesDB if ( !infoRet ) infoRet = info; @@ -2556,12 +2354,7 @@ const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale) wxString wxLocale::GetSysName() const { - // FIXME -#ifndef __WXWINCE__ return wxSetlocale(LC_ALL, NULL); -#else - return wxEmptyString; -#endif } // clean up @@ -2578,51 +2371,48 @@ wxLocale::~wxLocale() // restore old locale pointer wxSetLocale(m_pOldLocale); - // FIXME -#ifndef __WXWINCE__ wxSetlocale(LC_ALL, m_pszOldLocale); -#endif free((wxChar *)m_pszOldLocale); // const_cast } // 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() ) @@ -2630,83 +2420,94 @@ const wxChar *wxLocale::GetString(const wxChar *szOrigString, NoTransErr noTransErr; 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(""), + wxS("string \"%s\"[%ld] not found in %slocale '%s'."), + origString, (long)n, + wxString::Format(wxS("domain '%s' "), domain).c_str(), 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; } -wxString wxLocale::GetHeaderValue( const wxChar* szHeader, - const wxChar* szDomain ) const +WX_DECLARE_HASH_SET(wxString, wxStringHash, wxStringEqual, + wxLocaleUntranslatedStrings); + +/* static */ +const wxString& wxLocale::GetUntranslatedString(const wxString& str) { - if ( wxIsEmpty(szHeader) ) + 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 wxString& header, + const wxString& domain) const +{ + 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(wxS('\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; } @@ -2718,55 +2519,50 @@ wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const bool wxLocale::IsAvailable(int lang) { const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); - wxCHECK_MSG( info, false, _T("invalid language") ); + wxCHECK_MSG( info, false, wxS("invalid language") ); #if defined(__WIN32__) if ( !info->WinLang ) return false; - if ( !::IsValidLocale - ( - MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT), - LCID_INSTALLED - ) ) + if ( !::IsValidLocale(info->GetLCID(), LCID_INSTALLED) ) 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; @@ -2807,47 +2603,98 @@ bool wxLocale::AddCatalog(const wxChar *szDomain, // accessors for locale-dependent data // ---------------------------------------------------------------------------- -#ifdef __WXMSW__ +#if defined(__WXMSW__) /* static */ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) { + wxUint32 lcid = LOCALE_USER_DEFAULT; + + if (wxGetLocale()) + { + const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage()); + if ( info ) + lcid = info->GetLCID(); + } + wxString str; wxChar buffer[256]; size_t count; - buffer[0] = wxT('\0'); + buffer[0] = wxS('\0'); switch (index) { case wxLOCALE_DECIMAL_POINT: - count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buffer, 256); + count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256); if (!count) - str << wxT("."); + str << wxS("."); else str << buffer; break; #if 0 case wxSYS_LIST_SEPARATOR: - count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, buffer, 256); + count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256); if (!count) - str << wxT(","); + str << wxS(","); 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); + count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256); if (!count) - str << wxT("0"); + str << wxS("0"); else str << buffer; break; #endif default: - wxFAIL_MSG(wxT("Unknown System String !")); + wxFAIL_MSG(wxS("Unknown System String !")); } return str; } -#else // !__WXMSW__ +#elif defined(__DARWIN__) + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +{ + CFLocaleRef userLocaleRefRaw; + if ( wxGetLocale() ) + { + userLocaleRefRaw = CFLocaleCreate + ( + kCFAllocatorDefault, + wxCFStringRef(wxGetLocale()->GetCanonicalName()) + ); + } + else // no current locale, use the default one + { + userLocaleRefRaw = CFLocaleCopyCurrent(); + } + + wxCFRef userLocaleRef(userLocaleRefRaw); + + CFStringRef cfstr = 0; + switch ( index ) + { + case wxLOCALE_THOUSANDS_SEP: + cfstr = (CFStringRef) CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator); + break; + + case wxLOCALE_DECIMAL_POINT: + cfstr = (CFStringRef) CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); + break; + + default: + wxFAIL_MSG( "Unknown locale info" ); + cfstr = CFSTR(""); + break; + } + + wxCFStringRef str(wxCFRetain(cfstr)); + return str.AsString(); +} + +#else // !__WXMSW__ && !__DARWIN__ /* static */ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) @@ -2884,7 +2731,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) } } -#endif // __WXMSW__/!__WXMSW__ +#endif // platform // ---------------------------------------------------------------------------- // global functions and variables @@ -3106,6 +2953,9 @@ IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) #ifndef LANG_RUSSIAN #define LANG_RUSSIAN (0) #endif +#ifndef LANG_SAMI +#define LANG_SAMI (0) +#endif #ifndef LANG_SANSKRIT #define LANG_SANSKRIT (0) #endif @@ -3430,9 +3280,9 @@ IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) #define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \ info.Language = wxlang; \ - info.CanonicalName = wxT(canonical); \ + info.CanonicalName = wxS(canonical); \ info.LayoutDirection = layout; \ - info.Description = wxT(desc); \ + info.Description = wxS(desc); \ SETWINLANG(info, winlang, winsublang) \ AddLanguage(info); @@ -3525,7 +3375,7 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_FRENCH_SWISS, "fr_CH", LANG_FRENCH , SUBLANG_FRENCH_SWISS , wxLayout_LeftToRight, "French (Swiss)") LNG(wxLANGUAGE_FRISIAN, "fy" , 0 , 0 , wxLayout_LeftToRight, "Frisian") LNG(wxLANGUAGE_GALICIAN, "gl_ES", 0 , 0 , wxLayout_LeftToRight, "Galician") - LNG(wxLANGUAGE_GEORGIAN, "ka" , LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian") + LNG(wxLANGUAGE_GEORGIAN, "ka_GE", LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian") LNG(wxLANGUAGE_GERMAN, "de_DE", LANG_GERMAN , SUBLANG_GERMAN , wxLayout_LeftToRight, "German") LNG(wxLANGUAGE_GERMAN_AUSTRIAN, "de_AT", LANG_GERMAN , SUBLANG_GERMAN_AUSTRIAN , wxLayout_LeftToRight, "German (Austrian)") LNG(wxLANGUAGE_GERMAN_BELGIUM, "de_BE", 0 , 0 , wxLayout_LeftToRight, "German (Belgium)") @@ -3561,7 +3411,7 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_KIRUNDI, "rn" , 0 , 0 , wxLayout_LeftToRight, "Kirundi") LNG(wxLANGUAGE_KONKANI, "" , LANG_KONKANI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Konkani") LNG(wxLANGUAGE_KOREAN, "ko_KR", LANG_KOREAN , SUBLANG_KOREAN , wxLayout_LeftToRight, "Korean") - LNG(wxLANGUAGE_KURDISH, "ku" , 0 , 0 , wxLayout_LeftToRight, "Kurdish") + LNG(wxLANGUAGE_KURDISH, "ku_TR", 0 , 0 , wxLayout_LeftToRight, "Kurdish") LNG(wxLANGUAGE_LAOTHIAN, "lo" , 0 , 0 , wxLayout_LeftToRight, "Laothian") LNG(wxLANGUAGE_LATIN, "la" , 0 , 0 , wxLayout_LeftToRight, "Latin") LNG(wxLANGUAGE_LATVIAN, "lv_LV", LANG_LATVIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Latvian") @@ -3580,7 +3430,7 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_MOLDAVIAN, "mo" , 0 , 0 , wxLayout_LeftToRight, "Moldavian") LNG(wxLANGUAGE_MONGOLIAN, "mn" , 0 , 0 , wxLayout_LeftToRight, "Mongolian") LNG(wxLANGUAGE_NAURU, "na" , 0 , 0 , wxLayout_LeftToRight, "Nauru") - LNG(wxLANGUAGE_NEPALI, "ne" , LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali") + LNG(wxLANGUAGE_NEPALI, "ne_NP", LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali") LNG(wxLANGUAGE_NEPALI_INDIA, "ne_IN", LANG_NEPALI , SUBLANG_NEPALI_INDIA , wxLayout_LeftToRight, "Nepali (India)") LNG(wxLANGUAGE_NORWEGIAN_BOKMAL, "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL , wxLayout_LeftToRight, "Norwegian (Bokmal)") LNG(wxLANGUAGE_NORWEGIAN_NYNORSK, "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK , wxLayout_LeftToRight, "Norwegian (Nynorsk)") @@ -3597,12 +3447,16 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_ROMANIAN, "ro_RO", LANG_ROMANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Romanian") LNG(wxLANGUAGE_RUSSIAN, "ru_RU", LANG_RUSSIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Russian") LNG(wxLANGUAGE_RUSSIAN_UKRAINE, "ru_UA", 0 , 0 , wxLayout_LeftToRight, "Russian (Ukraine)") + LNG(wxLANGUAGE_SAMI, "se_NO", LANG_SAMI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Northern Sami") LNG(wxLANGUAGE_SAMOAN, "sm" , 0 , 0 , wxLayout_LeftToRight, "Samoan") LNG(wxLANGUAGE_SANGHO, "sg" , 0 , 0 , wxLayout_LeftToRight, "Sangho") LNG(wxLANGUAGE_SANSKRIT, "sa" , LANG_SANSKRIT , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sanskrit") LNG(wxLANGUAGE_SCOTS_GAELIC, "gd" , 0 , 0 , wxLayout_LeftToRight, "Scots Gaelic") + LNG(wxLANGUAGE_SERBIAN, "sr_SR", LANG_SERBIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Serbian") + LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_SR", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") + LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_SR@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") - LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") + LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") LNG(wxLANGUAGE_SERBO_CROATIAN, "sh" , 0 , 0 , wxLayout_LeftToRight, "Serbo-Croatian") LNG(wxLANGUAGE_SESOTHO, "st" , 0 , 0 , wxLayout_LeftToRight, "Sesotho") LNG(wxLANGUAGE_SETSWANA, "tn" , 0 , 0 , wxLayout_LeftToRight, "Setswana") @@ -3659,6 +3513,7 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_UZBEK, "uz" , LANG_UZBEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Uzbek") LNG(wxLANGUAGE_UZBEK_CYRILLIC, "uz" , LANG_UZBEK , SUBLANG_UZBEK_CYRILLIC , wxLayout_LeftToRight, "Uzbek (Cyrillic)") LNG(wxLANGUAGE_UZBEK_LATIN, "uz" , LANG_UZBEK , SUBLANG_UZBEK_LATIN , wxLayout_LeftToRight, "Uzbek (Latin)") + LNG(wxLANGUAGE_VALENCIAN, "ca_ES@valencia", 0 , 0 , wxLayout_LeftToRight, "Valencian") LNG(wxLANGUAGE_VIETNAMESE, "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Vietnamese") LNG(wxLANGUAGE_VOLAPUK, "vo" , 0 , 0 , wxLayout_LeftToRight, "Volapuk") LNG(wxLANGUAGE_WELSH, "cy" , 0 , 0 , wxLayout_LeftToRight, "Welsh")