X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c801d85f158c4cba50b588807daabdcbd0ed3853..1f2f0331455e0a91fdbc57afefe8f8c7c0db9392:/src/common/intl.cpp?ds=sidebyside diff --git a/src/common/intl.cpp b/src/common/intl.cpp index b5520e58b7..3d3ca71c45 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -46,8 +46,8 @@ // ---------------------------------------------------------------------------- // magic number identifying the .mo format file -const uint32 MSGCATALOG_MAGIC = 0x950412de; -const uint32 MSGCATALOG_MAGIC_SW = 0xde120495; +const size_t32 MSGCATALOG_MAGIC = 0x950412de; +const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495; // extension of ".mo" files #define MSGCATALOG_EXTENSION ".mo" @@ -104,40 +104,40 @@ private: // an entry in the string table struct wxMsgTableEntry { - uint32 nLen; // length of the string - uint32 ofsString; // pointer to the string + size_t32 nLen; // length of the string + size_t32 ofsString; // pointer to the string }; // header of a .mo file struct wxMsgCatalogHeader { - uint32 magic, // offset +00: magic id + size_t32 magic, // offset +00: magic id revision, // +04: revision numStrings; // +08: number of strings in the file - uint32 ofsOrigTable, // +0C: start of original string table + size_t32 ofsOrigTable, // +0C: start of original string table ofsTransTable; // +10: start of translated string table - uint32 nHashSize, // +14: hash table size + size_t32 nHashSize, // +14: hash table size ofsHashTable; // +18: offset of hash table start }; // all data is stored here, NULL if no data loaded - uint8 *m_pData; + size_t8 *m_pData; // data description - uint32 m_numStrings, // number of strings in this domain + size_t32 m_numStrings, // number of strings in this domain m_nHashSize; // number of entries in hash table - uint32 *m_pHashTable; // pointer to hash table + size_t32 *m_pHashTable; // pointer to hash table wxMsgTableEntry *m_pOrigTable, // pointer to original strings *m_pTransTable; // translated - const char *StringAtOfs(wxMsgTableEntry *pTable, uint32 index) const + const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 index) const { return (const char *)(m_pData + Swap(pTable[index].ofsString)); } // utility functions // calculate the hash value of given string - static inline uint32 GetHash(const char *sz); + static inline size_t32 GetHash(const char *sz); // big<->little endian - inline uint32 Swap(uint32 ui) const; + inline size_t32 Swap(size_t32 ui) const; // internal state bool HasHashTable() const // true if hash table is present @@ -148,6 +148,13 @@ private: char *m_pszName; // name of the domain }; +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// the list of the directories to search for message catalog files +static wxArrayString s_searchPrefixes; + // ============================================================================ // implementation // ============================================================================ @@ -158,16 +165,16 @@ private: // calculate hash value using the so called hashpjw function by P.J. Weinberger // [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools] -uint32 wxMsgCatalog::GetHash(const char *sz) +size_t32 wxMsgCatalog::GetHash(const char *sz) { - #define HASHWORDBITS 32 // the length of uint32 + #define HASHWORDBITS 32 // the length of size_t32 - uint32 hval = 0; - uint32 g; + size_t32 hval = 0; + size_t32 g; while ( *sz != '\0' ) { hval <<= 4; - hval += (uint32)*sz++; - g = hval & ((uint32)0xf << (HASHWORDBITS - 4)); + hval += (size_t32)*sz++; + g = hval & ((size_t32)0xf << (HASHWORDBITS - 4)); if ( g != 0 ) { hval ^= g >> (HASHWORDBITS - 8); hval ^= g; @@ -178,7 +185,7 @@ uint32 wxMsgCatalog::GetHash(const char *sz) } // swap the 2 halves of 32 bit integer if needed -uint32 wxMsgCatalog::Swap(uint32 ui) const +size_t32 wxMsgCatalog::Swap(size_t32 ui) const { return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) | ((ui >> 8) & 0xff00) | (ui >> 24) @@ -193,46 +200,81 @@ wxMsgCatalog::wxMsgCatalog() wxMsgCatalog::~wxMsgCatalog() { - DELETEA(m_pData); - DELETEA(m_pszName); + wxDELETEA(m_pData); + wxDELETEA(m_pszName); } +// small class to suppress the translation erros until exit from current scope class NoTransErr { - public: +public: NoTransErr() { wxSuppressTransErrors(); } ~NoTransErr() { wxRestoreTransErrors(); } }; +// return all directories to search for given prefix +static wxString GetAllMsgCatalogSubdirs(const char *prefix, + const char *lang) +{ + wxString searchPath; + + // search first in prefix/fr/LC_MESSAGES, then in prefix/fr and finally in + // prefix (assuming the language is 'fr') + searchPath << prefix << FILE_SEP_PATH << lang << FILE_SEP_PATH + << "LC_MESSAGES" << PATH_SEP + << prefix << FILE_SEP_PATH << lang << PATH_SEP + << prefix << PATH_SEP; + + return searchPath; +} + +// construct the search path for the given language +static wxString GetFullSearchPath(const char *lang) +{ + wxString searchPath; + + // first take the entries explicitly added by the program + size_t count = s_searchPrefixes.Count(); + for ( size_t n = 0; n < count; n++ ) + { + searchPath << GetAllMsgCatalogSubdirs(s_searchPrefixes[n], lang) + << PATH_SEP; + } + + // then take the current directory + // FIXME it should be the directory of the executable + searchPath << GetAllMsgCatalogSubdirs(".", lang) << PATH_SEP; + + // and finally add some standard ones + searchPath + << GetAllMsgCatalogSubdirs("/usr/share/locale", lang) << PATH_SEP + << GetAllMsgCatalogSubdirs("/usr/lib/locale", lang) << PATH_SEP + << GetAllMsgCatalogSubdirs("/usr/local/share/locale", lang); + + return searchPath; +} + // open disk file and read in it's contents bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) { - // search order (assume language 'foo') is - // 1) $LC_PATH/foo/LC_MESSAGES (if LC_PATH set) - // 2) ./foo/LC_MESSAGES - // 3) ./foo - // 4) . (Added by JACS) - // - // under UNIX we search also in: - // 5) /usr/share/locale/foo/LC_MESSAGES (Linux) - // 6) /usr/lib/locale/foo/LC_MESSAGES (Solaris) - #define MSG_PATH FILE_SEP_PATH + "LC_MESSAGES" PATH_SEP - - wxString strPath(""); + // FIXME VZ: I forgot the exact meaning of LC_PATH - anyone to remind me? +#if 0 const char *pszLcPath = getenv("LC_PATH"); if ( pszLcPath != NULL ) - strPath += pszLcPath + wxString(szDirPrefix) + MSG_PATH; // (1) + strPath += pszLcPath + wxString(szDirPrefix) + MSG_PATH; +#endif // 0 - // NB: '<<' is unneeded between too literal strings: - // they are concatenated at compile time - strPath += "./" + wxString(szDirPrefix) + MSG_PATH // (2) - + "./" + szDirPrefix + FILE_SEP_PATH + PATH_SEP // (3) - + "." + PATH_SEP - #ifdef __UNIX__ - "/usr/share/locale/" + szDirPrefix + MSG_PATH // (5) - "/usr/lib/locale/" + szDirPrefix + MSG_PATH // (6) - #endif //UNIX - ; + wxString searchPath = GetFullSearchPath(szDirPrefix); + const char *sublocale = strchr(szDirPrefix, '_'); + if ( sublocale ) + { + // 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 << GetFullSearchPath(wxString(szDirPrefix). + Left((size_t)(sublocale - szDirPrefix))) + << PATH_SEP; + } wxString strFile = szName; strFile += MSGCATALOG_EXTENSION; @@ -243,17 +285,17 @@ bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) // (we're using an object because we have several return paths) NoTransErr noTransErr; - wxLogVerbose("looking for catalog '%s' in path '%s'.", - szName, strPath.c_str()); + wxLogVerbose(_("looking for catalog '%s' in path '%s'."), + szName, searchPath.c_str()); wxString strFullName; - if ( !wxFindFileInPath(&strFullName, strPath, strFile) ) { - wxLogWarning("catalog file for domain '%s' not found.", szName); + if ( !wxFindFileInPath(&strFullName, searchPath, strFile) ) { + wxLogWarning(_("catalog file for domain '%s' not found."), szName); return FALSE; } // open file - wxLogVerbose("using catalog '%s' from '%s'.", + wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str()); wxFile fileMsg(strFullName); @@ -262,24 +304,21 @@ bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) // get the file size off_t nSize = fileMsg.Length(); - if ( nSize == ofsInvalid ) + if ( nSize == wxInvalidOffset ) return FALSE; // read the whole file in memory - m_pData = new uint8[nSize]; + m_pData = new size_t8[nSize]; if ( fileMsg.Read(m_pData, nSize) != nSize ) { - DELETEA(m_pData); - m_pData = NULL; + wxDELETEA(m_pData); return FALSE; } // examine header bool bValid = (size_t)nSize > sizeof(wxMsgCatalogHeader); - wxMsgCatalogHeader *pHeader; + wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData; if ( bValid ) { - pHeader = (wxMsgCatalogHeader *)m_pData; - // we'll have to swap all the integers if it's true m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW; @@ -289,10 +328,9 @@ bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) if ( !bValid ) { // it's either too short or has incorrect magic number - wxLogWarning("'%s' is not a valid message catalog.", strFullName.c_str()); + wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str()); - DELETEA(m_pData); - m_pData = NULL; + wxDELETEA(m_pData); return FALSE; } @@ -304,7 +342,7 @@ bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) Swap(pHeader->ofsTransTable)); m_nHashSize = Swap(pHeader->nHashSize); - m_pHashTable = (uint32 *)(m_pData + Swap(pHeader->ofsHashTable)); + m_pHashTable = (size_t32 *)(m_pData + Swap(pHeader->ofsHashTable)); m_pszName = new char[strlen(szName) + 1]; strcpy(m_pszName, szName); @@ -320,13 +358,13 @@ const char *wxMsgCatalog::GetString(const char *szOrig) const return NULL; if ( HasHashTable() ) { // use hash table for lookup if possible - uint32 nHashVal = GetHash(szOrig); - uint32 nIndex = nHashVal % m_nHashSize; + size_t32 nHashVal = GetHash(szOrig); + size_t32 nIndex = nHashVal % m_nHashSize; - uint32 nIncr = 1 + (nHashVal % (m_nHashSize - 2)); + size_t32 nIncr = 1 + (nHashVal % (m_nHashSize - 2)); while ( TRUE ) { - uint32 nStr = Swap(m_pHashTable[nIndex]); + size_t32 nStr = Swap(m_pHashTable[nIndex]); if ( nStr == 0 ) return NULL; @@ -340,7 +378,7 @@ const char *wxMsgCatalog::GetString(const char *szOrig) const } } else { // no hash table: use default binary search - uint32 bottom = 0, + size_t32 bottom = 0, top = m_numStrings, current; while ( bottom < top ) { @@ -363,25 +401,33 @@ const char *wxMsgCatalog::GetString(const char *szOrig) const // wxLocale // ---------------------------------------------------------------------------- -// NB: ctor has (desired) side effect of changing current locale -wxLocale::wxLocale(const char *szName, - const char *szShort, - const char *szLocale, - bool bLoadDefault) - : m_strLocale(szName), m_strShort(szShort) +wxLocale::wxLocale() { + m_pszOldLocale = NULL; + m_pMsgCat = NULL; +} + +// NB: this function has (desired) side effect of changing current locale +bool wxLocale::Init(const char *szName, + const char *szShort, + const char *szLocale, + bool bLoadDefault) +{ + m_strLocale = szName; + m_strShort = szShort; + // change current locale (default: same as long name) if ( szLocale == NULL ) szLocale = szName; m_pszOldLocale = setlocale(LC_ALL, szLocale); if ( m_pszOldLocale == NULL ) - wxLogError("locale '%s' can not be set.", szLocale); + wxLogError(_("locale '%s' can not be set."), szLocale); // the short name will be used to look for catalog files as well, // so we need something here if ( m_strShort.IsEmpty() ) { - // #### I don't know how these 2 letter abbreviations are formed, - // this wild guess is almost surely wrong + // FIXME I don't know how these 2 letter abbreviations are formed, + // this wild guess is surely wrong m_strShort = wxToLower(szLocale[0]) + wxToLower(szLocale[1]); } @@ -390,24 +436,36 @@ wxLocale::wxLocale(const char *szName, // load the default catalog with wxWindows standard messages m_pMsgCat = NULL; + bool bOk = TRUE; if ( bLoadDefault ) - AddCatalog("wxstd"); + bOk = AddCatalog("wxstd"); + + return bOk; +} + +void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) +{ + if ( s_searchPrefixes.Index(prefix) == wxNOT_FOUND ) + { + s_searchPrefixes.Add(prefix); + } + //else: already have it } // clean up wxLocale::~wxLocale() { - // free memory - wxMsgCatalog *pTmpCat; - while ( m_pMsgCat != NULL ) { - pTmpCat = m_pMsgCat; - m_pMsgCat = m_pMsgCat->m_pNext; - delete pTmpCat; - } - - // restore old locale - wxSetLocale(m_pOldLocale); - setlocale(LC_ALL, m_pszOldLocale); + // free memory + wxMsgCatalog *pTmpCat; + while ( m_pMsgCat != NULL ) { + pTmpCat = m_pMsgCat; + m_pMsgCat = m_pMsgCat->m_pNext; + delete pTmpCat; + } + + // restore old locale + wxSetLocale(m_pOldLocale); + setlocale(LC_ALL, m_pszOldLocale); } // get the translation of given string in current locale @@ -437,16 +495,27 @@ const char *wxLocale::GetString(const char *szOrigString, if ( pszTrans == NULL ) { if ( wxIsLoggingTransErrors() ) { - // suppress further error messages - // (do it before LogWarning to prevent infinite recursion!) + // suppress further error messages if we're not debugging: this avoids + // flooding the user with messages about each and every missing string if, + // for example, a whole catalog file is missing. + + // do it before calling LogWarning to prevent infinite recursion! +#ifdef __WXDEBUG__ + NoTransErr noTransErr; +#else // !debug wxSuppressTransErrors(); +#endif // debug/!debug if ( szDomain != NULL ) - wxLogWarning("string '%s' not found in domain '%s' for locale '%s'.", - szOrigString, szDomain, m_strLocale.c_str()); + { + wxLogWarning(_("string '%s' not found in domain '%s' for locale '%s'."), + szOrigString, szDomain, m_strLocale.c_str()); + } else - wxLogWarning("string '%s' not found in locale '%s'.", - szOrigString, m_strLocale.c_str()); + { + wxLogWarning(_("string '%s' not found in locale '%s'."), + szOrigString, m_strLocale.c_str()); + } } return szOrigString;