X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0fb67cd1968707f15341792406da62045e11c5f0..0f05afccede840e04872bfc82103b689b8edc447:/src/common/intl.cpp?ds=inline diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 8954ce3384..272d7f3f63 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -28,6 +28,8 @@ #pragma hdrstop #endif +#if wxUSE_INTL + // standard headers #include #include @@ -38,6 +40,7 @@ #include "wx/intl.h" #include "wx/file.h" #include "wx/log.h" +#include "wx/debug.h" #include "wx/utils.h" #include @@ -46,9 +49,44 @@ // simple types // ---------------------------------------------------------------------------- -// FIXME adjust if necessary +// this should *not* be wxChar, this type must have exactly 8 bits! typedef unsigned char size_t8; -typedef unsigned long size_t32; + +#ifdef __WXMSW__ + #if defined(__WIN16__) + typedef unsigned long size_t32; + #elif defined(__WIN32__) + typedef unsigned int size_t32; + #else + // Win64 will have different type sizes + #error "Please define a 32 bit type" + #endif +#else // !Windows + // SIZEOF_XXX are defined by configure + #if defined(SIZEOF_INT) && (SIZEOF_INT == 4) + typedef unsigned int size_t32; + #elif defined(SIZEOF_LONG) && (SIZEOF_LONG == 4) + typedef unsigned long size_t32; + #else + // assume sizeof(int) == 4 - what else can we do + typedef unsigned int size_t32; + + // ... but at least check it during run time + static class IntSizeChecker + { + public: + IntSizeChecker() + { + // Asserting a sizeof directly causes some compilers to + // issue a "using constant in a conditional expression" warning + size_t intsize = sizeof(int); + + wxASSERT_MSG( intsize == 4, + "size_t32 is incorrectly defined!" ); + } + } intsizechecker; + #endif +#endif // Win/!Win // ---------------------------------------------------------------------------- // constants @@ -59,23 +97,39 @@ const size_t32 MSGCATALOG_MAGIC = 0x950412de; const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495; // extension of ".mo" files -#define MSGCATALOG_EXTENSION ".mo" +#define MSGCATALOG_EXTENSION _T(".mo") // ---------------------------------------------------------------------------- // global functions // ---------------------------------------------------------------------------- -// suppress further error messages about missing translations -// (if you don't have one catalog file, you wouldn't like to see the -// error message for each string in it, so normally it's given only -// once) -void wxSuppressTransErrors(); +#ifdef __WXDEBUG__ -// restore the logging -void wxRestoreTransErrors(); +// small class to suppress the translation erros until exit from current scope +class NoTransErr +{ +public: + NoTransErr() { ms_suppressCount++; } + ~NoTransErr() { ms_suppressCount--; } -// get the current state -bool wxIsLoggingTransErrors(); + static bool Suppress() { return ms_suppressCount > 0; } + +private: + static size_t ms_suppressCount; +}; + +size_t NoTransErr::ms_suppressCount = 0; + +#else // !Debug + +class NoTransErr +{ +public: + NoTransErr() { } + ~NoTransErr() { } +}; + +#endif // Debug/!Debug static wxLocale *wxSetLocale(wxLocale *pLocale); @@ -94,11 +148,11 @@ public: ~wxMsgCatalog(); // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const char *szDirPrefix, const char *szName); + bool Load(const wxChar *szDirPrefix, const wxChar *szName, bool bConvertEncoding = FALSE); bool IsLoaded() const { return m_pData != NULL; } // get name of the catalog - const char *GetName() const { return m_pszName; } + const wxChar *GetName() const { return m_pszName; } // get the translated string: returns NULL if not found const char *GetString(const char *sz) const; @@ -141,6 +195,9 @@ private: const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 index) const { return (const char *)(m_pData + Swap(pTable[index].ofsString)); } + // convert encoding to platform native one, if neccessary + void ConvertEncoding(); + // utility functions // calculate the hash value of given string static inline size_t32 GetHash(const char *sz); @@ -153,7 +210,7 @@ private: bool m_bSwapped; // wrong endianness? - char *m_pszName; // name of the domain + wxChar *m_pszName; // name of the domain }; // ---------------------------------------------------------------------------- @@ -212,24 +269,16 @@ wxMsgCatalog::~wxMsgCatalog() wxDELETEA(m_pszName); } -// small class to suppress the translation erros until exit from current scope -class NoTransErr -{ -public: - NoTransErr() { wxSuppressTransErrors(); } - ~NoTransErr() { wxRestoreTransErrors(); } -}; - // return all directories to search for given prefix -static wxString GetAllMsgCatalogSubdirs(const char *prefix, - const char *lang) +static wxString GetAllMsgCatalogSubdirs(const wxChar *prefix, + const wxChar *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 << wxFILE_SEP_PATH << lang << wxFILE_SEP_PATH - << "LC_MESSAGES" << wxPATH_SEP + << wxT("LC_MESSAGES") << wxPATH_SEP << prefix << wxFILE_SEP_PATH << lang << wxPATH_SEP << prefix << wxPATH_SEP; @@ -237,7 +286,7 @@ static wxString GetAllMsgCatalogSubdirs(const char *prefix, } // construct the search path for the given language -static wxString GetFullSearchPath(const char *lang) +static wxString GetFullSearchPath(const wxChar *lang) { wxString searchPath; @@ -249,31 +298,38 @@ static wxString GetFullSearchPath(const char *lang) << wxPATH_SEP; } + // LC_PATH is a standard env var containing the search path for the .mo + // files + const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); + if ( pszLcPath != NULL ) + searchPath << GetAllMsgCatalogSubdirs(pszLcPath, lang); + // then take the current directory // FIXME it should be the directory of the executable - searchPath << GetAllMsgCatalogSubdirs(".", lang) << wxPATH_SEP; + searchPath << GetAllMsgCatalogSubdirs(wxT("."), lang); // and finally add some standard ones searchPath - << GetAllMsgCatalogSubdirs("/usr/share/locale", lang) << wxPATH_SEP - << GetAllMsgCatalogSubdirs("/usr/lib/locale", lang) << wxPATH_SEP - << GetAllMsgCatalogSubdirs("/usr/local/share/locale", lang); + << GetAllMsgCatalogSubdirs(wxT("/usr/share/locale"), lang) + << GetAllMsgCatalogSubdirs(wxT("/usr/lib/locale"), lang) + << GetAllMsgCatalogSubdirs(wxT("/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) +bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName0, bool bConvertEncoding) { - // 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; -#endif // 0 + /* We need to handle locales like de_AT.iso-8859-1 + For this we first chop off the .CHARSET specifier and ignore it. + FIXME: UNICODE SUPPORT: must use CHARSET specifier! + */ + wxString szName = szName0; + if(szName.Find(wxT('.')) != -1) // contains a dot + szName = szName.Left(szName.Find(wxT('.'))); wxString searchPath = GetFullSearchPath(szDirPrefix); - const char *sublocale = strchr(szDirPrefix, '_'); + const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_')); if ( sublocale ) { // also add just base locale name: for things like "fr_BE" (belgium @@ -291,20 +347,20 @@ bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) // not yet be loaded (and it's normal) // // (we're using an object because we have several return paths) - NoTransErr noTransErr; + NoTransErr noTransErr; wxLogVerbose(_("looking for catalog '%s' in path '%s'."), - szName, searchPath.c_str()); + szName.c_str(), searchPath.c_str()); wxString strFullName; if ( !wxFindFileInPath(&strFullName, searchPath, strFile) ) { - wxLogWarning(_("catalog file for domain '%s' not found."), szName); + wxLogWarning(_("catalog file for domain '%s' not found."), szName.c_str()); return FALSE; } // open file wxLogVerbose(_("using catalog '%s' from '%s'."), - szName, strFullName.c_str()); + szName.c_str(), strFullName.c_str()); wxFile fileMsg(strFullName); if ( !fileMsg.IsOpened() ) @@ -352,8 +408,11 @@ bool wxMsgCatalog::Load(const char *szDirPrefix, const char *szName) m_nHashSize = Swap(pHeader->nHashSize); m_pHashTable = (size_t32 *)(m_pData + Swap(pHeader->ofsHashTable)); - m_pszName = new char[strlen(szName) + 1]; - strcpy(m_pszName, szName); + m_pszName = new wxChar[wxStrlen(szName) + 1]; + wxStrcpy(m_pszName, szName); + + if (bConvertEncoding) + ConvertEncoding(); // everything is fine return TRUE; @@ -371,7 +430,13 @@ const char *wxMsgCatalog::GetString(const char *szOrig) const size_t32 nIncr = 1 + (nHashVal % (m_nHashSize - 2)); - while ( TRUE ) { +#if defined(__VISAGECPP__) +// VA just can't stand while(1) or while(TRUE) + bool bOs2var = TRUE; + while(bOs2var) { +#else + while (1) { +#endif size_t32 nStr = Swap(m_pHashTable[nIndex]); if ( nStr == 0 ) return NULL; @@ -405,6 +470,53 @@ const char *wxMsgCatalog::GetString(const char *szOrig) const return NULL; } + +#if wxUSE_GUI +#include "wx/fontmap.h" +#include "wx/encconv.h" +#endif + +void wxMsgCatalog::ConvertEncoding() +{ +#if wxUSE_GUI + wxFontEncoding enc; + + // first, find encoding header: + const char *hdr = StringAtOfs(m_pOrigTable, 0); + if (hdr == NULL) return; // not supported by this catalog, does not have non-fuzzy header + if (hdr[0] != 0) return; // ditto + + /* we support catalogs with header (msgid "") that is _not_ marked as "#, fuzzy" (otherwise + the string would not be included into compiled catalog) */ + wxString header(StringAtOfs(m_pTransTable, 0)); + wxString charset; + int pos = header.Find(wxT("Content-Type: text/plain; charset=")); + if (pos == wxNOT_FOUND) + return; // incorrectly filled Content-Type header + size_t n = pos + 34; /*strlen("Content-Type: text/plain; charset=")*/ + while (header[n] != wxT('\n')) + charset << header[n++]; + + enc = wxTheFontMapper->CharsetToEncoding(charset, FALSE); + if ( enc == wxFONTENCODING_SYSTEM ) + return; // unknown encoding + + wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc); + if (a[0] == enc) + return; // no conversion needed, locale uses native encoding + + if (a.GetCount() == 0) + return; // we don't know common equiv. under this platform + + wxEncodingConverter converter; + + converter.Init(enc, a[0]); + for (size_t i = 0; i < m_numStrings; i++) + converter.Convert((char*)StringAtOfs(m_pTransTable, i)); +#endif +} + + // ---------------------------------------------------------------------------- // wxLocale // ---------------------------------------------------------------------------- @@ -416,18 +528,23 @@ wxLocale::wxLocale() } // 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) +bool wxLocale::Init(const wxChar *szName, + const wxChar *szShort, + const wxChar *szLocale, + bool bLoadDefault, + bool bConvertEncoding) { m_strLocale = szName; m_strShort = szShort; + m_bConvertEncoding = bConvertEncoding; // change current locale (default: same as long name) if ( szLocale == NULL ) - szLocale = szName; - m_pszOldLocale = setlocale(LC_ALL, szLocale); + { + // the argument to setlocale() + szLocale = szShort; + } + m_pszOldLocale = wxSetlocale(LC_ALL, szLocale); if ( m_pszOldLocale == NULL ) wxLogError(_("locale '%s' can not be set."), szLocale); @@ -446,7 +563,7 @@ bool wxLocale::Init(const char *szName, m_pMsgCat = NULL; bool bOk = TRUE; if ( bLoadDefault ) - bOk = AddCatalog("wxstd"); + bOk = AddCatalog(wxT("wxstd")); return bOk; } @@ -473,17 +590,22 @@ wxLocale::~wxLocale() // restore old locale wxSetLocale(m_pOldLocale); - setlocale(LC_ALL, m_pszOldLocale); + wxSetlocale(LC_ALL, m_pszOldLocale); } // get the translation of given string in current locale -const char *wxLocale::GetString(const char *szOrigString, - const char *szDomain) const +const wxMB2WXbuf wxLocale::GetString(const wxChar *szOrigString, + const wxChar *szDomain) const { - if ( IsEmpty(szOrigString) ) + if ( wxIsEmpty(szOrigString) ) return szDomain; const char *pszTrans = NULL; +#if wxUSE_UNICODE + const wxWX2MBbuf szOrgString = wxConvCurrent->cWX2MB(szOrigString); +#else // ANSI + #define szOrgString szOrigString +#endif // Unicode/ANSI wxMsgCatalog *pMsgCat; if ( szDomain != NULL ) { @@ -491,55 +613,53 @@ const char *wxLocale::GetString(const char *szOrigString, // does the catalog exist? if ( pMsgCat != NULL ) - pszTrans = pMsgCat->GetString(szOrigString); + pszTrans = pMsgCat->GetString(szOrgString); } else { // search in all domains for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) { - pszTrans = pMsgCat->GetString(szOrigString); + pszTrans = pMsgCat->GetString(szOrgString); if ( pszTrans != NULL ) // take the first found break; } } if ( pszTrans == NULL ) { - if ( wxIsLoggingTransErrors() ) { - // 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__ + if ( !NoTransErr::Suppress() ) { NoTransErr noTransErr; -#else // !debug - wxSuppressTransErrors(); -#endif // debug/!debug if ( szDomain != NULL ) { - wxLogWarning(_("string '%s' not found in domain '%s' for locale '%s'."), + wxLogDebug(_T("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()); + wxLogDebug(_T("string '%s' not found in locale '%s'."), + szOrigString, m_strLocale.c_str()); } } +#endif // __WXDEBUG__ - return szOrigString; + return (wxMB2WXbuf)(szOrigString); } else - return pszTrans; + { + return wxConvertMB2WX(pszTrans); // or preferably wxCSConv(charset).cMB2WX(pszTrans) or something, + // a macro similar to wxConvertMB2WX could be written for that + } + + #undef szOrgString } // find catalog by name in a linked list, return NULL if !found -wxMsgCatalog *wxLocale::FindCatalog(const char *szDomain) const +wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const { // linear search in the linked list wxMsgCatalog *pMsgCat; for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) { - if ( Stricmp(pMsgCat->GetName(), szDomain) == 0 ) + if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) return pMsgCat; } @@ -547,17 +667,17 @@ wxMsgCatalog *wxLocale::FindCatalog(const char *szDomain) const } // check if the given catalog is loaded -bool wxLocale::IsLoaded(const char *szDomain) const +bool wxLocale::IsLoaded(const wxChar *szDomain) const { return FindCatalog(szDomain) != NULL; } // add a catalog to our linked list -bool wxLocale::AddCatalog(const char *szDomain) +bool wxLocale::AddCatalog(const wxChar *szDomain) { wxMsgCatalog *pMsgCat = new wxMsgCatalog; - if ( pMsgCat->Load(m_strShort, szDomain) ) { + if ( pMsgCat->Load(m_strShort, szDomain, m_bConvertEncoding) ) { // add it to the head of the list so that in GetString it will // be searched before the catalogs added earlier pMsgCat->m_pNext = m_pMsgCat; @@ -577,26 +697,6 @@ bool wxLocale::AddCatalog(const char *szDomain) // global functions and variables // ---------------------------------------------------------------------------- -// translation errors logging -// -------------------------- - -static bool gs_bGiveTransErrors = TRUE; - -void wxSuppressTransErrors() -{ - gs_bGiveTransErrors = FALSE; -} - -void wxRestoreTransErrors() -{ - gs_bGiveTransErrors = TRUE; -} - -bool wxIsLoggingTransErrors() -{ - return gs_bGiveTransErrors; -} - // retrieve/change current locale // ------------------------------ @@ -614,3 +714,6 @@ wxLocale *wxSetLocale(wxLocale *pLocale) g_pLocale = pLocale; return pOld; } + +#endif // wxUSE_INTL +