#pragma hdrstop
#endif
+#if wxUSE_INTL
+
// standard headers
#include <locale.h>
#include <ctype.h>
#include "wx/intl.h"
#include "wx/file.h"
#include "wx/log.h"
+#include "wx/debug.h"
#include "wx/utils.h"
#include <stdlib.h>
public:
IntSizeChecker()
{
- wxASSERT_MSG( sizeof(int) == 4,
+ // 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;
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);
~wxMsgCatalog();
// load the catalog from disk (szDirPrefix corresponds to language)
- bool Load(const wxChar *szDirPrefix, const wxChar *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 *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);
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 wxChar *prefix,
const wxChar *lang)
// 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
- << _T("LC_MESSAGES") << wxPATH_SEP
+ << wxT("LC_MESSAGES") << wxPATH_SEP
<< prefix << wxFILE_SEP_PATH << lang << wxPATH_SEP
<< prefix << wxPATH_SEP;
<< 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(_T("."), lang) << wxPATH_SEP;
+ searchPath << GetAllMsgCatalogSubdirs(wxT("."), lang);
// and finally add some standard ones
searchPath
- << GetAllMsgCatalogSubdirs(_T("/usr/share/locale"), lang) << wxPATH_SEP
- << GetAllMsgCatalogSubdirs(_T("/usr/lib/locale"), lang) << wxPATH_SEP
- << GetAllMsgCatalogSubdirs(_T("/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 wxChar *szDirPrefix, const wxChar *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 wxChar *pszLcPath = wxGetenv("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 wxChar *sublocale = wxStrchr(szDirPrefix, _T('_'));
+ const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_'));
if ( sublocale )
{
// also add just base locale name: for things like "fr_BE" (belgium
// 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() )
m_pszName = new wxChar[wxStrlen(szName) + 1];
wxStrcpy(m_pszName, szName);
+ if (bConvertEncoding)
+ ConvertEncoding();
+
// everything is fine
return TRUE;
}
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;
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
// ----------------------------------------------------------------------------
bool wxLocale::Init(const wxChar *szName,
const wxChar *szShort,
const wxChar *szLocale,
- bool bLoadDefault)
+ 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;
+ {
+ // the argument to setlocale()
+ szLocale = szShort;
+ }
m_pszOldLocale = wxSetlocale(LC_ALL, szLocale);
if ( m_pszOldLocale == NULL )
wxLogError(_("locale '%s' can not be set."), szLocale);
m_pMsgCat = NULL;
bool bOk = TRUE;
if ( bLoadDefault )
- bOk = AddCatalog(_T("wxstd"));
+ bOk = AddCatalog(wxT("wxstd"));
return bOk;
}
// get the translation of given string in current locale
const wxMB2WXbuf wxLocale::GetString(const wxChar *szOrigString,
- const wxChar *szDomain) const
+ const wxChar *szDomain) const
{
if ( wxIsEmpty(szOrigString) )
return szDomain;
const char *pszTrans = NULL;
- const wxWX2MBbuf szOrgString = wxConv_libc.cWX2MB(szOrigString);
+#if wxUSE_UNICODE
+ const wxWX2MBbuf szOrgString = wxConvCurrent->cWX2MB(szOrigString);
+#else // ANSI
+ #define szOrgString szOrigString
+#endif // Unicode/ANSI
wxMsgCatalog *pMsgCat;
if ( szDomain != NULL ) {
}
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 (wxMB2WXbuf)(szOrigString);
}
else
- return (wxMB2WXbuf)(wxConv_libc.cMB2WX(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 *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;
// 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
// ------------------------------
g_pLocale = pLocale;
return pOld;
}
+
+#endif // wxUSE_INTL
+