X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4178000933f0618d2cc9dc2f80dfed91b0c61464..d7a7bd6d27cf2d3bb23c5ceeccbcbe74cf83b4ec:/src/common/intl.cpp?ds=sidebyside diff --git a/src/common/intl.cpp b/src/common/intl.cpp index be3b4f65b9..3f592d7881 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: intl.cpp +// Name: src/common/intl.cpp // Purpose: Internationalization and localisation for wxWindows // Author: Vadim Zeitlin // Modified by: @@ -31,69 +31,47 @@ #if wxUSE_INTL // standard headers -#include -#include +#include +#include +#include +#ifdef HAVE_LANGINFO_H + #include +#endif // wxWindows -#include "wx/defs.h" -#include "wx/string.h" -#include "wx/tokenzr.h" -#include "wx/intl.h" +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/debug.h" + #include "wx/utils.h" + #include "wx/dynarray.h" +#endif // WX_PRECOMP + #include "wx/file.h" -#include "wx/log.h" -#include "wx/debug.h" -#include "wx/utils.h" -#include "wx/dynarray.h" +#include "wx/tokenzr.h" #include "wx/module.h" +#include "wx/fontmap.h" +#include "wx/encconv.h" +#include "wx/hashmap.h" + #ifdef __WIN32__ -#include "wx/msw/private.h" + #include "wx/msw/private.h" +#elif defined(__UNIX_LIKE__) + #include "wx/fontmap.h" // for CharsetToEncoding() #endif - -#include +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif // ---------------------------------------------------------------------------- // simple types // ---------------------------------------------------------------------------- // this should *not* be wxChar, this type must have exactly 8 bits! -typedef unsigned char size_t8; - -#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 +typedef wxUint8 size_t8; +typedef wxUint32 size_t32; // ---------------------------------------------------------------------------- // constants @@ -162,8 +140,73 @@ static inline wxString ExtractNotLang(const wxString& langFull) #endif // __UNIX__ + +// ---------------------------------------------------------------------------- +// wxMsgCatalogFile corresponds to one disk-file message catalog. +// +// This is a "low-level" class and is used only by wxMsgCatalog +// ---------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash) + +class wxMsgCatalogFile +{ +public: + // ctor & dtor + wxMsgCatalogFile(); + ~wxMsgCatalogFile(); + + // load the catalog from disk (szDirPrefix corresponds to language) + bool Load(const wxChar *szDirPrefix, const wxChar *szName); + + // fills the hash with string-translation pairs + void FillHash(wxMessagesHash& hash, bool convertEncoding) const; + +private: + // this implementation is binary compatible with GNU gettext() version 0.10 + + // an entry in the string table + struct wxMsgTableEntry + { + size_t32 nLen; // length of the string + size_t32 ofsString; // pointer to the string + }; + + // header of a .mo file + struct wxMsgCatalogHeader + { + size_t32 magic, // offset +00: magic id + revision, // +04: revision + numStrings; // +08: number of strings in the file + size_t32 ofsOrigTable, // +0C: start of original string table + ofsTransTable; // +10: start of translated string table + size_t32 nHashSize, // +14: hash table size + ofsHashTable; // +18: offset of hash table start + }; + + // all data is stored here, NULL if no data loaded + size_t8 *m_pData; + + // data description + size_t32 m_numStrings; // number of strings in this domain + wxMsgTableEntry *m_pOrigTable, // pointer to original strings + *m_pTransTable; // translated + + const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 index) const + { return (const char *)(m_pData + Swap(pTable[index].ofsString)); } + + wxString GetCharset() const; + + // utility functions + // big<->little endian + inline size_t32 Swap(size_t32 ui) const; + + bool m_bSwapped; // wrong endianness? +}; + + // ---------------------------------------------------------------------------- -// wxMsgCatalog corresponds to one disk-file message catalog. +// wxMsgCatalog corresponds to one loaded message catalog. // // This is a "low-level" class and is used only by wxLocale (that's why // it's designed to be stored in a linked list) @@ -172,74 +215,21 @@ static inline wxString ExtractNotLang(const wxString& langFull) class wxMsgCatalog { public: - // ctor & dtor - wxMsgCatalog(); - ~wxMsgCatalog(); + // load the catalog from disk (szDirPrefix corresponds to language) + bool Load(const wxChar *szDirPrefix, const wxChar *szName, bool bConvertEncoding = FALSE); - // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const wxChar *szDirPrefix, const wxChar *szName, bool bConvertEncoding = FALSE); - bool IsLoaded() const { return m_pData != NULL; } + // get name of the catalog + wxString GetName() const { return m_name; } - // get name of the catalog - const wxChar *GetName() const { return m_pszName; } + // get the translated string: returns NULL if not found + const wxChar *GetString(const wxChar *sz) const; - // get the translated string: returns NULL if not found - const char *GetString(const char *sz) const; - - // public variable pointing to the next element in a linked list (or NULL) - wxMsgCatalog *m_pNext; + // public variable pointing to the next element in a linked list (or NULL) + wxMsgCatalog *m_pNext; private: - // this implementation is binary compatible with GNU gettext() version 0.10 - - // an entry in the string table - struct wxMsgTableEntry - { - size_t32 nLen; // length of the string - size_t32 ofsString; // pointer to the string - }; - - // header of a .mo file - struct wxMsgCatalogHeader - { - size_t32 magic, // offset +00: magic id - revision, // +04: revision - numStrings; // +08: number of strings in the file - size_t32 ofsOrigTable, // +0C: start of original string table - ofsTransTable; // +10: start of translated string table - size_t32 nHashSize, // +14: hash table size - ofsHashTable; // +18: offset of hash table start - }; - - // all data is stored here, NULL if no data loaded - size_t8 *m_pData; - - // data description - size_t32 m_numStrings, // number of strings in this domain - m_nHashSize; // number of entries in 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, 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 size_t32 GetHash(const char *sz); - // big<->little endian - inline size_t32 Swap(size_t32 ui) const; - - // internal state - bool HasHashTable() const // true if hash table is present - { return m_nHashSize > 2 && m_pHashTable != NULL; } - - bool m_bSwapped; // wrong endianness? - - wxChar *m_pszName; // name of the domain + wxMessagesHash m_messages; // all messages in the catalog + wxString m_name; // name of the domain }; // ---------------------------------------------------------------------------- @@ -254,48 +244,25 @@ static wxArrayString s_searchPrefixes; // ============================================================================ // ---------------------------------------------------------------------------- -// wxMsgCatalog class +// wxMsgCatalogFile class // ---------------------------------------------------------------------------- -// calculate hash value using the so called hashpjw function by P.J. Weinberger -// [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools] -size_t32 wxMsgCatalog::GetHash(const char *sz) -{ - #define HASHWORDBITS 32 // the length of size_t32 - - size_t32 hval = 0; - size_t32 g; - while ( *sz != '\0' ) { - hval <<= 4; - hval += (size_t32)*sz++; - g = hval & ((size_t32)0xf << (HASHWORDBITS - 4)); - if ( g != 0 ) { - hval ^= g >> (HASHWORDBITS - 8); - hval ^= g; - } - } - - return hval; -} - // swap the 2 halves of 32 bit integer if needed -size_t32 wxMsgCatalog::Swap(size_t32 ui) const +size_t32 wxMsgCatalogFile::Swap(size_t32 ui) const { return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) | ((ui >> 8) & 0xff00) | (ui >> 24) : ui; } -wxMsgCatalog::wxMsgCatalog() +wxMsgCatalogFile::wxMsgCatalogFile() { - m_pData = NULL; - m_pszName = NULL; + m_pData = NULL; } -wxMsgCatalog::~wxMsgCatalog() +wxMsgCatalogFile::~wxMsgCatalogFile() { wxDELETEA(m_pData); - wxDELETEA(m_pszName); } // return all directories to search for given prefix @@ -335,19 +302,30 @@ static wxString GetFullSearchPath(const wxChar *lang) // then take the current directory // FIXME it should be the directory of the executable +#ifdef __WXMAC__ + wxChar cwd[512] ; + wxGetWorkingDirectory( cwd , sizeof( cwd ) ) ; + searchPath << GetAllMsgCatalogSubdirs(cwd, lang); + // generic search paths could be somewhere in the system folder preferences +#else // !Mac searchPath << GetAllMsgCatalogSubdirs(wxT("."), lang); +#ifdef __UNIX__ // and finally add some standard ones searchPath + << GetAllMsgCatalogSubdirs(wxString(wxGetInstallPrefix()) + wxT("/share/locale"), lang) << GetAllMsgCatalogSubdirs(wxT("/usr/share/locale"), lang) << GetAllMsgCatalogSubdirs(wxT("/usr/lib/locale"), lang) << GetAllMsgCatalogSubdirs(wxT("/usr/local/share/locale"), lang); +#endif // __UNIX__ + +#endif // platform return searchPath; } // open disk file and read in it's contents -bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName0, bool bConvertEncoding) +bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0) { /* We need to handle locales like de_AT.iso-8859-1 For this we first chop off the .CHARSET specifier and ignore it. @@ -434,139 +412,152 @@ bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName0, bool b m_pTransTable = (wxMsgTableEntry *)(m_pData + Swap(pHeader->ofsTransTable)); - m_nHashSize = Swap(pHeader->nHashSize); - m_pHashTable = (size_t32 *)(m_pData + Swap(pHeader->ofsHashTable)); - - m_pszName = new wxChar[wxStrlen(szName) + 1]; - wxStrcpy(m_pszName, szName); - - if (bConvertEncoding) - ConvertEncoding(); - // everything is fine return TRUE; } -// search for a string -const char *wxMsgCatalog::GetString(const char *szOrig) const +void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) const { - if ( szOrig == NULL ) - return NULL; + wxString charset = GetCharset(); - if ( HasHashTable() ) { // use hash table for lookup if possible - size_t32 nHashVal = GetHash(szOrig); - size_t32 nIndex = nHashVal % m_nHashSize; +#if wxUSE_WCHAR_T + wxCSConv *csConv = NULL; + if ( !!charset ) + csConv = new wxCSConv(charset); - size_t32 nIncr = 1 + (nHashVal % (m_nHashSize - 2)); + wxMBConv& inputConv = csConv ? *((wxMBConv*)csConv) : *wxConvCurrent; - for ( ;; ) { - size_t32 nStr = Swap(m_pHashTable[nIndex]); - if ( nStr == 0 ) - return NULL; - - if ( strcmp(szOrig, StringAtOfs(m_pOrigTable, nStr - 1)) == 0 ) { - // work around for BC++ 5.5 bug: without a temp var, the optimizer - // breaks the code and the return value is incorrect - const char *tmp = StringAtOfs(m_pTransTable, nStr - 1); - return tmp; - } + for (size_t i = 0; i < m_numStrings; i++) + { + wxString key(StringAtOfs(m_pOrigTable, i), inputConv); - if ( nIndex >= m_nHashSize - nIncr) - nIndex -= m_nHashSize - nIncr; - else - nIndex += nIncr; - } - } - else { // no hash table: use default binary search - size_t32 bottom = 0, - top = m_numStrings, - current; - while ( bottom < top ) { - current = (bottom + top) / 2; - int res = strcmp(szOrig, StringAtOfs(m_pOrigTable, current)); - if ( res < 0 ) - top = current; - else if ( res > 0 ) - bottom = current + 1; - else { // found! - // work around the same BC++ 5.5 bug as above - const char *tmp = StringAtOfs(m_pTransTable, current); - return tmp; - } + #if wxUSE_UNICODE + hash[key] = wxString(StringAtOfs(m_pTransTable, i), inputConv); + #else + if ( convertEncoding ) + hash[key] = + wxString(inputConv.cMB2WC(StringAtOfs(m_pTransTable, i)), + wxConvLocal); + else + hash[key] = StringAtOfs(m_pTransTable, i); + #endif } - } - // not found - return NULL; -} + delete csConv; +#else // !wxUSE_WCHAR_T + #if wxUSE_FONTMAP + if ( convertEncoding ) + { + wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM; + wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(charset, FALSE); + if ( enc == wxFONTENCODING_SYSTEM ) + { + convertEncoding = FALSE; // unknown encoding + } + else + { + targetEnc = wxLocale::GetSystemEncoding(); + if (targetEnc == wxFONTENCODING_SYSTEM) + { + wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc); + if (a[0] == enc) + // no conversion needed, locale uses native encoding + convertEncoding = FALSE; + if (a.GetCount() == 0) + // we don't know common equiv. under this platform + convertEncoding = FALSE; + targetEnc = a[0]; + } + } + if ( convertEncoding ) + { + wxEncodingConverter converter; + converter.Init(enc, targetEnc); -#if wxUSE_GUI -#include "wx/fontmap.h" -#include "wx/encconv.h" -#endif + for (size_t i = 0; i < m_numStrings; i++) + { + wxString key(StringAtOfs(m_pOrigTable, i)); + hash[key] = + converter.Convert(wxString(StringAtOfs(m_pTransTable, i))); + } + } + } -void wxMsgCatalog::ConvertEncoding() -{ -#if wxUSE_GUI - wxFontEncoding enc; + if ( !convertEncoding ) + #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP + { + for (size_t i = 0; i < m_numStrings; i++) + { + wxString key(StringAtOfs(m_pOrigTable, i)); + hash[key] = StringAtOfs(m_pTransTable, i); + } + } +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T +} +wxString wxMsgCatalogFile::GetCharset() const +{ // first, find encoding header: const char *hdr = StringAtOfs(m_pOrigTable, 0); - if ( hdr == NULL || hdr[0] != 0 ) { - // not supported by this catalog, does not have non-fuzzy header - return; + if ( hdr == NULL || hdr[0] != 0 ) + { + // not supported by this catalog, does not have correct header + return wxEmptyString; } - /* - 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 + if ( pos == wxNOT_FOUND ) + { + // incorrectly filled Content-Type header + return wxEmptyString; + } + size_t n = pos + 34; /*strlen("Content-Type: text/plain; charset=")*/ - while (header[n] != wxT('\n')) + while ( header[n] != wxT('\n') ) charset << header[n++]; - enc = wxTheFontMapper->CharsetToEncoding(charset, FALSE); - if ( enc == wxFONTENCODING_SYSTEM ) - return; // unknown encoding - - wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM; -#ifdef __UNIX__ - wxString langFull; - if (wxGetEnv(wxT("LC_ALL"), &langFull) || - wxGetEnv(wxT("LC_CTYPE"), &langFull) || - wxGetEnv(wxT("LANG"), &langFull)) + if ( charset == wxT("CHARSET") ) { - wxString lcharset = langFull.AfterFirst(wxT('.')).BeforeFirst(wxT('@')); - if (!lcharset.IsEmpty()) - targetEnc = wxTheFontMapper->CharsetToEncoding(lcharset, FALSE); + // "CHARSET" is not valid charset, but lazy translator + return wxEmptyString; } -#endif - if (targetEnc == wxFONTENCODING_SYSTEM) + return charset; +} + +// ---------------------------------------------------------------------------- +// wxMsgCatalog class +// ---------------------------------------------------------------------------- + +bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, + bool bConvertEncoding) +{ + wxMsgCatalogFile file; + + m_name = szName; + + if ( file.Load(szDirPrefix, szName) ) { - 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 - targetEnc = a[0]; + file.FillHash(m_messages, bConvertEncoding); + return TRUE; } - wxEncodingConverter converter; - converter.Init(enc, targetEnc); - - for (size_t i = 0; i < m_numStrings; i++) - converter.Convert((char*)StringAtOfs(m_pTransTable, i)); -#endif // wxUSE_GUI + return FALSE; } +const wxChar *wxMsgCatalog::GetString(const wxChar *sz) const +{ + wxMessagesHash::const_iterator i = m_messages.find(sz); + if ( i != m_messages.end() ) + { + return i->second.c_str(); + } + else + return NULL; +} // ---------------------------------------------------------------------------- // wxLocale @@ -628,7 +619,12 @@ bool wxLocale::Init(const wxChar *szName, if ( m_strShort.IsEmpty() ) { // FIXME I don't know how these 2 letter abbreviations are formed, // this wild guess is surely wrong - m_strShort = tolower(szLocale[0]) + tolower(szLocale[1]); + if ( szLocale[0] ) + { + m_strShort += (wxChar)wxTolower(szLocale[0]); + if ( szLocale[1] ) + m_strShort += (wxChar)wxTolower(szLocale[1]); + } } // save the old locale to be able to restore it later @@ -684,10 +680,10 @@ bool wxLocale::Init(int language, int flags) wxString name = info->Description; wxString canonical = info->CanonicalName; wxString locale; - wxChar *retloc; + const wxChar *retloc; // Set the locale: -#ifdef __UNIX__ +#if defined(__UNIX__) && !defined(__WXMAC__) if (language == wxLANGUAGE_DEFAULT) locale = wxEmptyString; else @@ -768,7 +764,8 @@ bool wxLocale::Init(int language, int flags) wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); return FALSE; } - +#elif defined(__WXMAC__) + retloc = wxSetlocale(LC_ALL , wxEmptyString); #else return FALSE; #endif @@ -797,7 +794,7 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) size_t i = 0, count = ms_languagesDB->GetCount(); -#if defined(__UNIX__) +#if defined(__UNIX__) && !defined(__WXMAC__) // first get the string identifying the language from the environment wxString langFull; if (!wxGetEnv(wxT("LC_ALL"), &langFull) && @@ -808,7 +805,7 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) return wxLANGUAGE_ENGLISH; } - if ( langFull == _T("C") ) + if ( langFull == _T("C") || langFull == _T("POSIX") ) { // default C locale return wxLANGUAGE_ENGLISH; @@ -816,18 +813,31 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) // the language string has the following form // - // lang[_LANG[.encoding]] + // lang[_LANG][.encoding][@modifier] // - // where lang is the primary language, LANG is a sublang + // (see environ(5) in the Open Unix specification) + // + // where lang is the primary language, LANG is a sublang/territory, + // encoding is the charset to use and modifier "allows the user to select + // a specific instance of localization data within a single category" // // for example, the following strings are valid: // fr // fr_FR // de_DE.iso88591 + // de_DE@euro + // de_DE.iso88591@euro // for now we don't use the encoding, although we probably should (doing // translations of the msg catalogs on the fly as required) (TODO) - langFull = langFull.BeforeFirst(_T('.')); + // + // we don't use the modifiers neither but we probably should translate + // "euro" into iso885915 + size_t posEndLang = langFull.find_first_of(_T("@.")); + if ( posEndLang != wxString::npos ) + { + langFull.Truncate(posEndLang); + } // in addition to the format above, we also can have full language names // in LANG env var - for example, SuSE is known to use LANG="german" - so @@ -906,6 +916,292 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) } } } +#elif defined(__WXMAC__) + const char* lc = NULL ; + long lang = GetScriptVariable( smSystemScript, smScriptLang) ; + switch( GetScriptManagerVariable( smRegionCode ) ) { + case verUS : + lc = "en_US" ; + break ; + case verFrance : + lc = "fr_FR" ; + break ; + case verBritain : + lc = "en_GB" ; + break ; + case verGermany : + lc = "de_DE" ; + break ; + case verItaly : + lc = "it_IT" ; + break ; + case verNetherlands : + lc = "nl_NL" ; + break ; + case verFlemish : + lc = "nl_BE" ; + break ; + case verSweden : + lc = "sv_SE" ; + break ; + case verSpain : + lc = "es_ES" ; + break ; + case verDenmark : + lc = "da_DK" ; + break ; + case verPortugal : + lc = "pt_PT" ; + break ; + case verFrCanada: + lc = "fr_CA" ; + break ; + case verNorway: + lc = "no_NO" ; + break ; + case verIsrael: + lc = "iw_IL" ; + break ; + case verJapan: + lc = "ja_JP" ; + break ; + case verAustralia: + lc = "en_AU" ; + break ; + case verArabic: + lc = "ar" ; + break ; + case verFinland: + lc = "fi_FI" ; + break ; + case verFrSwiss: + lc = "fr_CH" ; + break ; + case verGrSwiss: + lc = "de_CH" ; + break ; + case verGreece: + lc = "el_GR" ; + break ; + case verIceland: + lc = "is_IS" ; + break ; + case verMalta: + lc = "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 = "el_GR" ; + } + else if ( lang == langTurkish ) { + lc = "tr_TR" ; + } + break ; + case verTurkey: + lc = "tr_TR" ; + break ; + case verYugoCroatian: + lc = "hr_HR" ; + break ; + case verIndiaHindi: + lc = "hi_IN" ; + break ; + case verPakistanUrdu: + lc = "ur_PK" ; + break ; + case verTurkishModified: + lc = "tr_TR" ; + break ; + case verItalianSwiss: + lc = "it_CH" ; + break ; + case verInternational: + lc = "en" ; + break ; + case verRomania: + lc = "ro_RO" ; + break ; + case verGreecePoly: + lc = "el_GR" ; + break ; + case verLithuania: + lc = "lt_LT" ; + break ; + case verPoland: + lc = "pl_PL" ; + break ; + case verMagyar : + case verHungary: + lc = "hu_HU" ; + break ; + case verEstonia: + lc = "et_EE" ; + break ; + case verLatvia: + lc = "lv_LV" ; + break ; + case verSami: + // not known + break ; + case verFaroeIsl: + lc = "fo_FO" ; + break ; + case verIran: + lc = "fa_IR" ; + break ; + case verRussia: + lc = "ru_RU" ; + break ; + case verIreland: + lc = "ga_IE" ; + break ; + case verKorea: + lc = "ko_KR" ; + break ; + case verChina: + lc = "zh_CN" ; + break ; + case verTaiwan: + lc = "zh_TW" ; + break ; + case verThailand: + lc = "th_TH" ; + break ; + case verCzech: + lc = "cs_CZ" ; + break ; + case verSlovak: + lc = "sk_SK" ; + break ; + case verBengali: + lc = "bn" ; + break ; + case verByeloRussian: + lc = "be_BY" ; + break ; + case verUkraine: + lc = "uk_UA" ; + break ; + case verGreeceAlt: + lc = "el_GR" ; + break ; + case verSerbian: + lc = "sr_YU" ; + break ; + case verSlovenian: + lc = "sl_SI" ; + break ; + case verMacedonian: + lc = "mk_MK" ; + break ; + case verCroatia: + lc = "hr_HR" ; + break ; + case verBrazil: + lc = "pt_BR " ; + break ; + case verBulgaria: + lc = "bg_BG" ; + break ; + case verCatalonia: + lc = "ca_ES" ; + break ; + case verScottishGaelic: + lc = "gd" ; + break ; + case verManxGaelic: + lc = "gv" ; + break ; + case verBreton: + lc = "br" ; + break ; + case verNunavut: + lc = "iu_CA" ; + break ; + case verWelsh: + lc = "cy" ; + break ; + case verIrishGaelicScript: + lc = "ga_IE" ; + break ; + case verEngCanada: + lc = "en_CA" ; + break ; + case verBhutan: + lc = "dz_BT" ; + break ; + case verArmenian: + lc = "hy_AM" ; + break ; + case verGeorgian: + lc = "ka_GE" ; + break ; + case verSpLatinAmerica: + lc = "es_AR" ; + break ; + case verTonga: + lc = "to_TO" ; + break ; + case verFrenchUniversal: + lc = "fr_FR" ; + break ; + case verAustria: + lc = "de_AT" ; + break ; + case verGujarati: + lc = "gu_IN" ; + break ; + case verPunjabi: + lc = "pa" ; + break ; + case verIndiaUrdu: + lc = "ur_IN" ; + break ; + case verVietnam: + lc = "vi_VN" ; + break ; + case verFrBelgium: + lc = "fr_BE" ; + break ; + case verUzbek: + lc = "uz_UZ" ; + break ; + case verSingapore: + lc = "zh_SG" ; + break ; + case verNynorsk: + lc = "nn_NO" ; + break ; + case verAfrikaans: + lc = "af_ZA" ; + break ; + case verEsperanto: + lc = "eo" ; + break ; + case verMarathi: + lc = "mr_IN" ; + break ; + case verTibetan: + lc = "bo" ; + break ; + case verNepal: + lc = "ne_NP" ; + break ; + case verGreenland: + lc = "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 ) @@ -935,6 +1231,140 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) return wxLANGUAGE_UNKNOWN; } +// ---------------------------------------------------------------------------- +// encoding stuff +// ---------------------------------------------------------------------------- + +// this is a bit strange as under Windows we get the encoding name using its +// numeric value and under Unix we do it the other way round, but this just +// reflects the way different systems provide he encoding info + +/* static */ +wxString wxLocale::GetSystemEncodingName() +{ + wxString encname; + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // FIXME: what is the error return value for GetACP()? + UINT codepage = ::GetACP(); + encname.Printf(_T("windows-%u"), codepage); +#elif defined(__UNIX_LIKE__) + +#if defined(HAVE_LANGINFO_H) && defined(CODESET) + // GNU libc provides current character set this way (this conforms + // to Unix98) + char *oldLocale = strdup(setlocale(LC_CTYPE, NULL)); + setlocale(LC_CTYPE, ""); + char *alang = nl_langinfo(CODESET); + setlocale(LC_CTYPE, oldLocale); + free(oldLocale); + + if ( alang ) + { + // 7 bit ASCII encoding has several alternative names which we should + // recognize to avoid warnings about unrecognized encoding on each + // program startup + + // nl_langinfo() under Solaris returns 646 by default which stands for + // ISO-646, i.e. 7 bit ASCII + // + // and recent glibc call it ANSI_X3.4-1968... + if ( strcmp(alang, "646") == 0 || + strcmp(alang, "ANSI_X3.4-1968") == 0 ) + { + encname = _T("US-ASCII"); + } + else + { + encname = wxConvLibc.cMB2WX(alang); + } + } + else +#endif // HAVE_LANGINFO_H + { + // if we can't get at the character set directly, try to see if it's in + // the environment variables (in most cases this won't work, but I was + // out of ideas) + wxChar *lang = wxGetenv(wxT("LC_ALL")); + wxChar *dot = lang ? wxStrchr(lang, wxT('.')) : (wxChar *)NULL; + if (!dot) + { + lang = wxGetenv(wxT("LC_CTYPE")); + if ( lang ) + dot = wxStrchr(lang, wxT('.')); + } + if (!dot) + { + lang = wxGetenv(wxT("LANG")); + if ( lang ) + dot = wxStrchr(lang, wxT('.')); + } + + if ( dot ) + { + encname = dot+1; + } + } +#endif // Win32/Unix + + return encname; +} + +/* static */ +wxFontEncoding wxLocale::GetSystemEncoding() +{ +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + UINT codepage = ::GetACP(); + + // wxWindows only knows about CP1250-1257, 932, 936, 949, 950 + if ( codepage >= 1250 && codepage <= 1257 ) + { + return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250); + } + + if ( codepage == 932 ) + { + return wxFONTENCODING_CP932; + } + + if ( codepage == 936 ) + { + return wxFONTENCODING_CP936; + } + + if ( codepage == 949 ) + { + return wxFONTENCODING_CP949; + } + + if ( codepage == 950 ) + { + return wxFONTENCODING_CP950; + } +#elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP + wxString encname = GetSystemEncodingName(); + if ( !encname.empty() ) + { + wxFontEncoding enc = wxFontMapper::Get()-> + CharsetToEncoding(encname, FALSE /* not interactive */); + + // this should probably be considered as a bug in CharsetToEncoding(): + // it shouldn't return wxFONTENCODING_DEFAULT at all - but it does it + // for US-ASCII charset + // + // we, OTOH, definitely shouldn't return it as it doesn't make sense at + // all (which encoding is it?) + if ( enc != wxFONTENCODING_DEFAULT ) + { + return enc; + } + //else: return wxFONTENCODING_SYSTEM below + } +#endif // Win32/Unix + + return wxFONTENCODING_SYSTEM; +} + /*static*/ void wxLocale::AddLanguage(const wxLanguageInfo& info) { CreateLanguagesDB(); @@ -963,76 +1393,74 @@ wxLocale::~wxLocale() } // get the translation of given string in current locale -const wxMB2WXbuf wxLocale::GetString(const wxChar *szOrigString, - const wxChar *szDomain) const +const wxChar *wxLocale::GetString(const wxChar *szOrigString, + const wxChar *szDomain) const { - 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 ) { - pMsgCat = FindCatalog(szDomain); - - // does the catalog exist? - if ( pMsgCat != NULL ) - pszTrans = pMsgCat->GetString(szOrgString); - } - else { - // search in all domains - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) { - pszTrans = pMsgCat->GetString(szOrgString); - if ( pszTrans != NULL ) // take the first found - break; + if ( wxIsEmpty(szOrigString) ) + return _T(""); + + const wxChar *pszTrans = NULL; + wxMsgCatalog *pMsgCat; + + if ( szDomain != NULL ) + { + pMsgCat = FindCatalog(szDomain); + + // does the catalog exist? + if ( pMsgCat != NULL ) + pszTrans = pMsgCat->GetString(szOrigString); + } + else + { + // search in all domains + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + pszTrans = pMsgCat->GetString(szOrigString); + if ( pszTrans != NULL ) // take the first found + break; + } } - } - if ( pszTrans == NULL ) { + if ( pszTrans == NULL ) + { #ifdef __WXDEBUG__ - if ( !NoTransErr::Suppress() ) { - NoTransErr noTransErr; + if ( !NoTransErr::Suppress() ) + { + NoTransErr noTransErr; - if ( szDomain != NULL ) - { - wxLogDebug(_T("string '%s' not found in domain '%s' for locale '%s'."), - szOrigString, szDomain, m_strLocale.c_str()); - } - else - { - wxLogDebug(_T("string '%s' not found in locale '%s'."), - szOrigString, m_strLocale.c_str()); - } - } + if ( szDomain != NULL ) + { + wxLogTrace(_T("i18n"), + _T("string '%s' not found in domain '%s' for locale '%s'."), + szOrigString, szDomain, m_strLocale.c_str()); + } + else + { + wxLogTrace(_T("i18n"), + _T("string '%s' not found in locale '%s'."), + szOrigString, m_strLocale.c_str()); + } + } #endif // __WXDEBUG__ - return (wxMB2WXbuf)(szOrigString); - } - else - { - return wxConvertMB2WX(pszTrans); // or preferably wxCSConv(charset).cMB2WX(pszTrans) or something, - // a macro similar to wxConvertMB2WX could be written for that - } + return szOrigString; + } - #undef szOrgString + return pszTrans; } // find catalog by name in a linked list, return NULL if !found 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 ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) - return pMsgCat; - } + // linear search in the linked list + wxMsgCatalog *pMsgCat; + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) + return pMsgCat; + } - return NULL; + return NULL; } // check if the given catalog is loaded @@ -1062,6 +1490,62 @@ bool wxLocale::AddCatalog(const wxChar *szDomain) } } +// ---------------------------------------------------------------------------- +// accessors for locale-dependent data +// ---------------------------------------------------------------------------- + +#if 0 + +#ifdef __WXMSW__ + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index) +{ + wxString str; + wxChar buffer[256]; + size_t count; + buffer[0] = wxT('\0'); + switch (index) + { + case wxSYS_DECIMAL_SEPARATOR: + count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buffer, 256); + if (!count) + str << "."; + else + str << buffer; + break; + case wxSYS_LIST_SEPARATOR: + count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, buffer, 256); + if (!count) + str << ","; + 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); + if (!count) + str << "0"; + else + str << buffer; + break; + default: + wxFAIL_MSG("Unknown System String !"); + } + return str; +} + +#else // !__WXMSW__ + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory) +{ + return wxEmptyString; +} + +#endif // __WXMSW__/!__WXMSW__ + +#endif // 0 + // ---------------------------------------------------------------------------- // global functions and variables // ---------------------------------------------------------------------------- @@ -1114,7 +1598,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) // This table is generated by misc/languages/genlang.py // When making changes, please put them into misc/languages/langtabl.txt -#ifndef __WIN32__ +#if !defined(__WIN32__) || defined(__WXMICROWIN__) #define SETWINLANG(info,lang,sublang) @@ -1844,13 +2328,11 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_YORUBA, "yo" , 0 , 0 , "Yoruba") LNG(wxLANGUAGE_ZHUANG, "za" , 0 , 0 , "Zhuang") LNG(wxLANGUAGE_ZULU, "zu" , 0 , 0 , "Zulu") - + }; #undef LNG // --- --- --- generated code ends here --- --- --- - - #endif // wxUSE_INTL