X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8a942c3dd3de286de6e9f374c05712d7e5c43f6d..b6a20a20d010d643e52914f51aa0700df0da925f:/src/common/intl.cpp diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 67e446e66e..ac1b779ea4 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: src/common/intl.cpp -// Purpose: Internationalization and localisation for wxWindows +// Purpose: Internationalization and localisation for wxWidgets // Author: Vadim Zeitlin // Modified by: Michael N. Filippov // (2003/09/30 - PluralForms support) @@ -22,6 +22,18 @@ #pragma implementation "intl.h" #endif +#if defined(__BORLAND__) && !defined(__WXDEBUG__) + // There's a bug in Borland's compiler that breaks wxLocale with -O2, + // so make sure that flag is not used for this file: + #pragma option -O1 +#endif + +#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" @@ -43,7 +55,7 @@ #include #endif -// wxWindows +// wxWidgets #ifndef WX_PRECOMP #include "wx/string.h" #include "wx/intl.h" @@ -151,7 +163,7 @@ static inline wxString ExtractNotLang(const wxString& langFull) // Plural forms parser // ---------------------------------------------------------------------------- -/* +/* Simplified Grammar Expression: @@ -177,7 +189,7 @@ RelationalExpression: MultiplicativeExpression ">=" MultiplicativeExpression MultiplicativeExpression "<=" MultiplicativeExpression MultiplicativeExpression - + MultiplicativeExpression: PmExpression '%' PmExpression PmExpression @@ -389,7 +401,7 @@ private: wxPluralFormsToken m_token; wxPluralFormsNodePtr m_nodes[3]; }; - + wxPluralFormsNodePtr::~wxPluralFormsNodePtr() { delete m_p; @@ -474,7 +486,7 @@ class wxPluralFormsCalculator { public: wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {} - + // input: number, returns msgstr index int evaluate(int n) const; @@ -487,7 +499,7 @@ public: void init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural); wxString getString() const; - + private: wxPluralFormsToken::Number m_nplurals; wxPluralFormsNodePtr m_plural; @@ -529,7 +541,7 @@ private: wxPluralFormsScanner& m_scanner; const wxPluralFormsToken& token() const; bool nextToken(); - + wxPluralFormsNode* expression(); wxPluralFormsNode* logicalOrExpression(); wxPluralFormsNode* logicalAndExpression(); @@ -875,7 +887,8 @@ public: wxPluralFormsCalculatorPtr& rPluralFormsCalculator); // fills the hash with string-translation pairs - void FillHash(wxMessagesHash& hash, bool convertEncoding) const; + void FillHash(wxMessagesHash& hash, const wxString& msgIdCharset, + bool convertEncoding) const; private: // this implementation is binary compatible with GNU gettext() version 0.10 @@ -911,7 +924,7 @@ private: *m_pTransTable; // translated wxString m_charset; - + // swap the 2 halves of 32 bit integer if needed size_t32 Swap(size_t32 ui) const { @@ -932,7 +945,7 @@ private: } return (const char *)(m_pData + ofsString); - } + } bool m_bSwapped; // wrong endianness? @@ -951,7 +964,8 @@ class wxMsgCatalog { public: // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const wxChar *szDirPrefix, const wxChar *szName, bool bConvertEncoding = FALSE); + bool Load(const wxChar *szDirPrefix, const wxChar *szName, + const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false); // get name of the catalog wxString GetName() const { return m_name; } @@ -1144,7 +1158,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0, m_pTransTable = (wxMsgTableEntry *)(m_pData + Swap(pHeader->ofsTransTable)); m_nSize = nSize; - + // now parse catalog's header and try to extract catalog charset and // plural forms formula from it: @@ -1169,7 +1183,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0, } } // else: incorrectly filled Content-Type header - + // Extract plural forms: begin = header.Find(wxT("Plural-Forms:")); if (begin != wxNOT_FOUND) @@ -1202,7 +1216,9 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName0, return true; } -void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) const +void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, + const wxString& msgIdCharset, + bool convertEncoding) const { #if wxUSE_WCHAR_T wxCSConv *csConv = NULL; @@ -1210,7 +1226,15 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons csConv = new wxCSConv(m_charset); wxMBConv& inputConv = csConv ? *((wxMBConv*)csConv) : *wxConvCurrent; + + wxCSConv *sourceConv = NULL; + if ( !msgIdCharset.empty() && (m_charset != msgIdCharset) ) + sourceConv = new wxCSConv(msgIdCharset); + #elif wxUSE_FONTMAP + wxASSERT_MSG( msgIdCharset == NULL, + _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); + wxEncodingConverter converter; if ( convertEncoding ) { @@ -1247,11 +1271,17 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons for (size_t i = 0; i < m_numStrings; i++) { const char *data = StringAtOfs(m_pOrigTable, i); -#if wxUSE_WCHAR_T +#if wxUSE_UNICODE wxString msgid(data, inputConv); #else - wxString msgid(data); + wxString msgid; +#if wxUSE_WCHAR_T + if ( convertEncoding && sourceConv ) + msgid = wxString(inputConv.cMB2WC(data), *sourceConv); + else #endif + msgid = data; +#endif // wxUSE_UNICODE data = StringAtOfs(m_pTransTable, i); size_t length = Swap(m_pTransTable[i].nLen); @@ -1288,6 +1318,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons } #if wxUSE_WCHAR_T + delete sourceConv; delete csConv; #endif } @@ -1298,7 +1329,7 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, bool convertEncoding) cons // ---------------------------------------------------------------------------- bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, - bool bConvertEncoding) + const wxChar *msgIdCharset, bool bConvertEncoding) { wxMsgCatalogFile file; @@ -1306,7 +1337,7 @@ bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, if ( file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) { - file.FillHash(m_messages, bConvertEncoding); + file.FillHash(m_messages, msgIdCharset, bConvertEncoding); return TRUE; } @@ -1364,7 +1395,7 @@ wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL; } -wxLocale::wxLocale() +void wxLocale::DoCommonInit() { m_pszOldLocale = NULL; m_pMsgCat = NULL; @@ -1381,7 +1412,7 @@ bool wxLocale::Init(const wxChar *szName, { wxASSERT_MSG( !m_initialized, _T("you can't call wxLocale::Init more than once") ); - + m_initialized = true; m_strLocale = szName; m_strShort = szShort; @@ -1404,7 +1435,7 @@ bool wxLocale::Init(const wxChar *szName, 256); if (ret != 0) { - m_pszOldLocale = wxStrdup(localeName); + m_pszOldLocale = wxStrdup(localeName); } else m_pszOldLocale = NULL; @@ -1412,9 +1443,11 @@ bool wxLocale::Init(const wxChar *szName, // TODO: how to find languageId // SetLocaleInfo(languageId, SORT_DEFAULT, localeName); #else - m_pszOldLocale = wxSetlocale(LC_ALL, szLocale); - if ( m_pszOldLocale ) - m_pszOldLocale = wxStrdup(m_pszOldLocale); + wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale); + if ( oldLocale ) + m_pszOldLocale = wxStrdup(oldLocale); + else + m_pszOldLocale = NULL; #endif if ( m_pszOldLocale == NULL ) @@ -1436,7 +1469,7 @@ bool wxLocale::Init(const wxChar *szName, // save the old locale to be able to restore it later m_pOldLocale = wxSetLocale(this); - // load the default catalog with wxWindows standard messages + // load the default catalog with wxWidgets standard messages m_pMsgCat = NULL; bool bOk = TRUE; if ( bLoadDefault ) @@ -1560,7 +1593,10 @@ bool wxLocale::Init(int language, int flags) // #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) { @@ -1571,7 +1607,7 @@ bool wxLocale::Init(int language, int flags) } else { - int codepage + int codepage #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS = -1 #endif @@ -2134,7 +2170,7 @@ void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) // 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 +// reflects the way different systems provide the encoding info /* static */ wxString wxLocale::GetSystemEncodingName() @@ -2166,8 +2202,18 @@ wxString wxLocale::GetSystemEncodingName() // 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 ) + // + // HP-UX uses HP-Roman8 cset which is not the same as ASCII (see RFC + // 1345 for its definition) but must be recognized as otherwise HP + // users get a warning about it on each program startup, so handle it + // here -- but it would be obviously better to add real supprot to it, + // of course! + if ( strcmp(alang, "646") == 0 + || strcmp(alang, "ANSI_X3.4-1968") == 0 +#ifdef __HPUX__ + || strcmp(alang, "roman8") == 0 +#endif // __HPUX__ + ) { encname = _T("US-ASCII"); } @@ -2213,7 +2259,7 @@ wxFontEncoding wxLocale::GetSystemEncoding() #if defined(__WIN32__) && !defined(__WXMICROWIN__) UINT codepage = ::GetACP(); - // wxWindows only knows about CP1250-1257, 932, 936, 949, 950 + // wxWidgets only knows about CP1250-1257, 932, 936, 949, 950 if ( codepage >= 1250 && codepage <= 1257 ) { return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250); @@ -2239,7 +2285,13 @@ wxFontEncoding wxLocale::GetSystemEncoding() return wxFONTENCODING_CP950; } #elif defined(__WXMAC__) - return wxMacGetFontEncFromSystemEnc( CFStringGetSystemEncoding() ) ; + TextEncoding encoding = 0 ; +#if TARGET_CARBON + encoding = CFStringGetSystemEncoding() ; +#else + UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ; +#endif + return wxMacGetFontEncFromSystemEnc( encoding ) ; #elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP wxString encname = GetSystemEncodingName(); if ( !encname.empty() ) @@ -2287,6 +2339,11 @@ const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang) { CreateLanguagesDB(); + // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so + // make it work + if ( lang == wxLANGUAGE_DEFAULT ) + lang = GetSystemLanguage(); + const size_t count = ms_languagesDB->GetCount(); for ( size_t i = 0; i < count; i++ ) { @@ -2422,15 +2479,16 @@ const wxChar *wxLocale::GetString(const wxChar *szOrigString, if ( szDomain != NULL ) { wxLogTrace(_T("i18n"), - _T("string '%s'[%d] not found in domain '%s' for locale '%s'."), - szOrigString, (int)n, szDomain, m_strLocale.c_str()); + _T("string '%s'[%lu] not found in domain '%s' for locale '%s'."), + szOrigString, (unsigned long)n, + szDomain, m_strLocale.c_str()); } else { wxLogTrace(_T("i18n"), - _T("string '%s'[%d] not found in locale '%s'."), - szOrigString, (int)n, m_strLocale.c_str()); + _T("string '%s'[%lu] not found in locale '%s'."), + szOrigString, (unsigned long)n, m_strLocale.c_str()); } } #endif // __WXDEBUG__ @@ -2444,6 +2502,58 @@ const wxChar *wxLocale::GetString(const wxChar *szOrigString, return pszTrans; } +wxString wxLocale::GetHeaderValue( const wxChar* szHeader, + const wxChar* szDomain ) const +{ + if ( wxIsEmpty(szHeader) ) + return wxEmptyString; + + wxChar const * pszTrans = NULL; + wxMsgCatalog *pMsgCat; + + if ( szDomain != NULL ) + { + pMsgCat = FindCatalog(szDomain); + + // does the catalog exist? + if ( pMsgCat == NULL ) + return wxEmptyString; + + pszTrans = pMsgCat->GetString(wxT(""), (size_t)-1); + } + else + { + // search in all domains + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + pszTrans = pMsgCat->GetString(wxT(""), (size_t)-1); + if ( pszTrans != NULL ) // take the first found + break; + } + } + + if ( wxIsEmpty(pszTrans) ) + return wxEmptyString; + + wxChar const * pszFound = wxStrstr(pszTrans, szHeader); + if ( pszFound == NULL ) + return wxEmptyString; + + pszFound += wxStrlen(szHeader) + 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 ); + + return retVal; +} + + // find catalog by name in a linked list, return NULL if !found wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const { @@ -2466,27 +2576,47 @@ bool wxLocale::IsLoaded(const wxChar *szDomain) const // add a catalog to our linked list bool wxLocale::AddCatalog(const wxChar *szDomain) +{ + return AddCatalog(szDomain, wxLANGUAGE_ENGLISH, NULL); +} + +// add a catalog to our linked list +bool wxLocale::AddCatalog(const wxChar *szDomain, + wxLanguage msgIdLanguage, + const wxChar *msgIdCharset) + { wxMsgCatalog *pMsgCat = new wxMsgCatalog; - if ( pMsgCat->Load(m_strShort, szDomain, m_bConvertEncoding) ) { + if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, 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; m_pMsgCat = pMsgCat; - return TRUE; + return true; } else { // don't add it because it couldn't be loaded anyway delete pMsgCat; - // it's OK to not load English catalog, the texts are embedded in - // the program: - if (m_strShort.Mid(0, 2) == wxT("en")) - return TRUE; + // It is OK to not load catalog if the msgid language and m_language match, + // in which case we can directly display the texts embedded in program's + // source code: + if (m_language == msgIdLanguage) + return true; - return FALSE; + // If there's no exact match, we may still get partial match where the + // (basic) language is same, but the country differs. For example, it's + // permitted to use en_US strings from sources even if m_language is en_GB: + const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage); + if ( msgIdLangInfo && + msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) ) + { + return true; + } + + return false; } } @@ -2494,12 +2624,10 @@ bool wxLocale::AddCatalog(const wxChar *szDomain) // accessors for locale-dependent data // ---------------------------------------------------------------------------- -#if 0 - #ifdef __WXMSW__ /* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index) +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) { wxString str; wxChar buffer[256]; @@ -2507,29 +2635,31 @@ wxString wxLocale::GetInfo(wxLocaleInfo index) buffer[0] = wxT('\0'); switch (index) { - case wxSYS_DECIMAL_SEPARATOR: + case wxLOCALE_DECIMAL_POINT: count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buffer, 256); if (!count) - str << "."; + str << wxT("."); else str << buffer; break; +#if 0 case wxSYS_LIST_SEPARATOR: count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, buffer, 256); if (!count) - str << ","; + str << wxT(","); 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"; + str << wxT("0"); else str << buffer; break; +#endif default: - wxFAIL_MSG("Unknown System String !"); + wxFAIL_MSG(wxT("Unknown System String !")); } return str; } @@ -2537,15 +2667,42 @@ wxString wxLocale::GetInfo(wxLocaleInfo index) #else // !__WXMSW__ /* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory) +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) { - return wxEmptyString; + struct lconv *locale_info = localeconv(); + switch (cat) + { + case wxLOCALE_CAT_NUMBER: + switch (index) + { + case wxLOCALE_THOUSANDS_SEP: + return wxString(locale_info->thousands_sep, + *wxConvCurrent); + case wxLOCALE_DECIMAL_POINT: + return wxString(locale_info->decimal_point, + *wxConvCurrent); + default: + return wxEmptyString; + } + case wxLOCALE_CAT_MONEY: + switch (index) + { + case wxLOCALE_THOUSANDS_SEP: + return wxString(locale_info->mon_thousands_sep, + *wxConvCurrent); + case wxLOCALE_DECIMAL_POINT: + return wxString(locale_info->mon_decimal_point, + *wxConvCurrent); + default: + return wxEmptyString; + } + default: + return wxEmptyString; + } } #endif // __WXMSW__/!__WXMSW__ -#endif // 0 - // ---------------------------------------------------------------------------- // global functions and variables // ---------------------------------------------------------------------------- @@ -3141,7 +3298,7 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_BURMESE, "my" , 0 , 0 , "Burmese") LNG(wxLANGUAGE_CAMBODIAN, "km" , 0 , 0 , "Cambodian") LNG(wxLANGUAGE_CATALAN, "ca_ES", LANG_CATALAN , SUBLANG_DEFAULT , "Catalan") - LNG(wxLANGUAGE_CHINESE, "zh_CN", LANG_CHINESE , SUBLANG_DEFAULT , "Chinese") + LNG(wxLANGUAGE_CHINESE, "zh_TW", LANG_CHINESE , SUBLANG_DEFAULT , "Chinese") LNG(wxLANGUAGE_CHINESE_SIMPLIFIED, "zh_CN", LANG_CHINESE , SUBLANG_CHINESE_SIMPLIFIED , "Chinese (Simplified)") LNG(wxLANGUAGE_CHINESE_TRADITIONAL, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , "Chinese (Traditional)") LNG(wxLANGUAGE_CHINESE_HONGKONG, "zh_HK", LANG_CHINESE , SUBLANG_CHINESE_HONGKONG , "Chinese (Hongkong)")