X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c88c6e94c01df742f16f19fb2dd63a490b4d57bf..0164f8ebfd7bbf1b0a96cb67641cd607c022ae9f:/src/common/intl.cpp diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 31332b83ba..d61d890e41 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -39,28 +39,27 @@ #if wxUSE_INTL -// standard headers +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/debug.h" + #include "wx/utils.h" + #include "wx/app.h" +#endif // WX_PRECOMP #ifndef __WXWINCE__ -#include + #include #endif +// standard headers #include #include #ifdef HAVE_LANGINFO_H - #include + #include #endif -// wxWidgets -#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 - #ifdef __WIN32__ #include "wx/msw/private.h" #elif defined(__UNIX_LIKE__) @@ -75,11 +74,11 @@ #include "wx/encconv.h" #include "wx/hashmap.h" #include "wx/ptr_scpd.h" -#include "wx/app.h" #include "wx/apptrait.h" +#include "wx/stdpaths.h" #if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers + #include "wx/mac/private.h" // includes mac headers #endif // ---------------------------------------------------------------------------- @@ -884,9 +883,14 @@ public: wxPluralFormsCalculatorPtr& rPluralFormsCalculator); // fills the hash with string-translation pairs - void FillHash(wxMessagesHash& hash, const wxString& msgIdCharset, + void FillHash(wxMessagesHash& hash, + const wxString& msgIdCharset, bool convertEncoding) const; + // return the charset of the strings in this catalog or empty string if + // none/unknown + wxString GetCharset() const { return m_charset; } + private: // this implementation is binary compatible with GNU gettext() version 0.10 @@ -920,7 +924,8 @@ private: wxMsgTableEntry *m_pOrigTable, // pointer to original strings *m_pTransTable; // translated - wxString m_charset; + wxString m_charset; // from the message catalog header + // swap the 2 halves of 32 bit integer if needed size_t32 Swap(size_t32 ui) const @@ -960,6 +965,9 @@ private: class wxMsgCatalog { public: + wxMsgCatalog() { m_conv = NULL; } + ~wxMsgCatalog(); + // load the catalog from disk (szDirPrefix corresponds to language) bool Load(const wxChar *szDirPrefix, const wxChar *szName, const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false); @@ -976,6 +984,11 @@ public: private: wxMessagesHash m_messages; // all messages in the catalog wxString m_name; // name of the domain + + // the conversion corresponding to this catalog charset if we installed it + // as the global one + wxCSConv *m_conv; + wxPluralFormsCalculatorPtr m_pluralFormsCalculator; }; @@ -984,7 +997,7 @@ private: // ---------------------------------------------------------------------------- // the list of the directories to search for message catalog files -static wxArrayString s_searchPrefixes; +static wxArrayString gs_searchPrefixes; // ============================================================================ // implementation @@ -1002,21 +1015,23 @@ wxMsgCatalogFile::wxMsgCatalogFile() wxMsgCatalogFile::~wxMsgCatalogFile() { - wxDELETEA(m_pData); + delete [] m_pData; } -// return all directories to search for given prefix -static wxString GetAllMsgCatalogSubdirs(const wxChar *prefix, - const wxChar *lang) +// return the directory to search for message catalogs under the given prefix +static +wxString GetMsgCatalogSubdir(const wxChar *prefix, const wxChar *lang) { wxString searchPath; + searchPath << prefix << wxFILE_SEP_PATH << 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 - << wxT("LC_MESSAGES") << wxPATH_SEP - << prefix << wxFILE_SEP_PATH << lang << wxPATH_SEP - << prefix << wxPATH_SEP; + // under Unix, the message catalogs are supposed to go into LC_MESSAGES + // subdirectory so look there too +#ifdef __UNIX__ + const wxString searchPathOrig(searchPath); + searchPath << wxFILE_SEP_PATH << wxT("LC_MESSAGES") + << wxPATH_SEP << searchPathOrig; +#endif // __UNIX__ return searchPath; } @@ -1024,48 +1039,59 @@ static wxString GetAllMsgCatalogSubdirs(const wxChar *prefix, // construct the search path for the given language static wxString GetFullSearchPath(const wxChar *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++ ) + wxArrayString paths; + paths.reserve(gs_searchPrefixes.size() + 1); + size_t n, + count = gs_searchPrefixes.size(); + for ( n = 0; n < count; n++ ) { - searchPath << GetAllMsgCatalogSubdirs(s_searchPrefixes[n], lang) - << wxPATH_SEP; + paths.Add(GetMsgCatalogSubdir(gs_searchPrefixes[n], lang)); } - // TODO: use wxStandardPaths instead of all this mess!! +#if wxUSE_STDPATHS + // then look in the standard location + const wxString stdp = wxStandardPaths::Get(). + GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); + + if ( paths.Index(stdp) == wxNOT_FOUND ) + paths.Add(stdp); +#endif // wxUSE_STDPATHS + + // last look in default locations +#ifdef __UNIX__ // LC_PATH is a standard env var containing the search path for the .mo // files -#ifndef __WXWINCE__ const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); - if ( pszLcPath != NULL ) - searchPath << GetAllMsgCatalogSubdirs(pszLcPath, lang); -#endif + if ( pszLcPath ) + { + const wxString lcp = GetMsgCatalogSubdir(pszLcPath, lang); + if ( paths.Index(lcp) == wxNOT_FOUND ) + paths.Add(lcp); + } -#ifdef __UNIX__ - // add some standard ones and the one in the tree where wxWin was installed: - 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); + // also add the one from where wxWin was installed: + wxString wxp = wxGetInstallPrefix(); + if ( !wxp.empty() ) + { + wxp = GetMsgCatalogSubdir(wxp + _T("/share/locale"), lang); + if ( paths.Index(wxp) == wxNOT_FOUND ) + paths.Add(wxp); + } #endif // __UNIX__ - // then take the current directory - // FIXME it should be the directory of the executable -#if defined(__WXMAC__) - searchPath << GetAllMsgCatalogSubdirs(wxGetCwd(), lang); - // generic search paths could be somewhere in the system folder preferences -#elif defined(__WXMSW__) - // look in the directory of the executable - wxString path; - wxSplitPath(wxGetFullModuleName(), &path, NULL, NULL); - searchPath << GetAllMsgCatalogSubdirs(path, lang); -#else // !Mac, !MSW - searchPath << GetAllMsgCatalogSubdirs(wxT("."), lang); -#endif // platform + + // finally construct the full search path + wxString searchPath; + searchPath.reserve(500); + count = paths.size(); + for ( n = 0; n < count; n++ ) + { + searchPath += paths[n]; + if ( n != count - 1 ) + searchPath += wxPATH_SEP; + } return searchPath; } @@ -1098,9 +1124,9 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, // 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))) - << wxPATH_SEP; + searchPath << wxPATH_SEP + << GetFullSearchPath(wxString(szDirPrefix). + Left((size_t)(sublocale - szDirPrefix))); } // don't give translation errors here because the wxstd catalog might @@ -1137,7 +1163,7 @@ bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, return false; size_t nSize = wx_truncate_cast(size_t, lenFile); - wxASSERT_MSG( nSize == lenFile, _T("message catalog bigger than 4GB?") ); + wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") ); // read the whole file in memory m_pData = new size_t8[nSize]; @@ -1234,10 +1260,14 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, const wxString& msgIdCharset, bool convertEncoding) const { -#if wxUSE_FONTMAP - // determine if we need any conversion at all +#if wxUSE_UNICODE + // this parameter doesn't make sense, we always must convert encoding in + // Unicode build + convertEncoding = true; +#elif wxUSE_FONTMAP if ( convertEncoding ) { + // determine if we need any conversion at all wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset); if ( encCat == wxLocale::GetSystemEncoding() ) { @@ -1245,23 +1275,26 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, convertEncoding = false; } } -#endif // wxUSE_FONTMAP +#endif // wxUSE_UNICODE/wxUSE_FONTMAP #if wxUSE_WCHAR_T // conversion to use to convert catalog strings to the GUI encoding wxMBConv *inputConv, - *csConv = NULL; // another ptr just to be able to delete it later - if ( convertEncoding ) + *inputConvPtr = NULL; // same as inputConv but safely deleteable + if ( convertEncoding && !m_charset.empty() ) { - if ( m_charset.empty() ) - inputConv = wxConvCurrent; - else - inputConv = - csConv = new wxCSConv(m_charset); + inputConvPtr = + inputConv = new wxCSConv(m_charset); } - else // no conversion needed + else // no need or not possible to convert the encoding { +#if wxUSE_UNICODE + // we must somehow convert the narrow strings in the message catalog to + // wide strings, so use the default conversion if we have no charset + inputConv = wxConvCurrent; +#else // !wxUSE_UNICODE inputConv = NULL; +#endif // wxUSE_UNICODE/!wxUSE_UNICODE } // conversion to apply to msgid strings before looking them up: we only @@ -1308,19 +1341,20 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T (void)convertEncoding; // get rid of warnings about unused parameter - for (size_t i = 0; i < m_numStrings; i++) + for (size_t32 i = 0; i < m_numStrings; i++) { const char *data = StringAtOfs(m_pOrigTable, i); + + wxString msgid; #if wxUSE_UNICODE - wxString msgid(data, *inputConv); + msgid = wxString(data, *inputConv); #else // ASCII - wxString msgid; -#if wxUSE_WCHAR_T - if ( inputConv && sourceConv ) - msgid = wxString(inputConv->cMB2WC(data), *sourceConv); - else -#endif - msgid = data; + #if wxUSE_WCHAR_T + if ( inputConv && sourceConv ) + msgid = wxString(inputConv->cMB2WC(data), *sourceConv); + else + #endif + msgid = data; #endif // wxUSE_UNICODE data = StringAtOfs(m_pTransTable, i); @@ -1329,38 +1363,40 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, size_t index = 0; while (offset < length) { + const char * const str = data + offset; + wxString msgstr; -#if wxUSE_WCHAR_T - #if wxUSE_UNICODE - msgstr = wxString(data + offset, *inputConv); - #else +#if wxUSE_UNICODE + msgstr = wxString(str, *inputConv); +#elif wxUSE_WCHAR_T if ( inputConv ) - msgstr = wxString(inputConv->cMB2WC(data + offset), wxConvLocal); + msgstr = wxString(inputConv->cMB2WC(str), *wxConvUI); else - msgstr = wxString(data + offset); - #endif + msgstr = str; #else // !wxUSE_WCHAR_T #if wxUSE_FONTMAP if ( convertEncoding ) - msgstr = wxString(converter.Convert(data + offset)); + msgstr = wxString(converter.Convert(str)); else #endif - msgstr = wxString(data + offset); + msgstr = str; #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T if ( !msgstr.empty() ) { hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr; } - offset += strlen(data + offset) + 1; + + // skip this string + offset += strlen(str) + 1; ++index; } } #if wxUSE_WCHAR_T delete sourceConv; - delete csConv; -#endif + delete inputConvPtr; +#endif // wxUSE_WCHAR_T } @@ -1368,6 +1404,21 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, // wxMsgCatalog class // ---------------------------------------------------------------------------- +wxMsgCatalog::~wxMsgCatalog() +{ + if ( m_conv ) + { + if ( wxConvUI == m_conv ) + { + // we only change wxConvUI if it points to wxConvLocal so we reset + // it back to it too + wxConvUI = &wxConvLocal; + } + + delete m_conv; + } +} + bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, const wxChar *msgIdCharset, bool bConvertEncoding) { @@ -1375,13 +1426,28 @@ bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, m_name = szName; - if ( file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) + if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) + return false; + + file.FillHash(m_messages, msgIdCharset, bConvertEncoding); + + // we should use a conversion compatible with the message catalog encoding + // in the GUI if we don't convert the strings to the current conversion but + // as the encoding is global, only change it once, otherwise we could get + // into trouble if we use several message catalogs with different encodings + // + // this is, of course, a hack but it at least allows the program to use + // message catalogs in any encodings without asking the user to change his + // locale + if ( !bConvertEncoding && + !file.GetCharset().empty() && + wxConvUI == &wxConvLocal ) { - file.FillHash(m_messages, msgIdCharset, bConvertEncoding); - return true; + wxConvUI = + m_conv = new wxCSConv(file.GetCharset()); } - return false; + return true; } const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const @@ -1591,60 +1657,83 @@ bool wxLocale::Init(int language, int flags) wxString locale; // Set the locale: -#if defined(__UNIX__) && !defined(__WXMAC__) - if (language == wxLANGUAGE_DEFAULT) - locale = wxEmptyString; - else +#if defined(__OS2__) + wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString); +#elif defined(__UNIX__) && !defined(__WXMAC__) + if (language != wxLANGUAGE_DEFAULT) locale = info->CanonicalName; wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); -#ifdef __AIX__ - // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL) - // can't be passed back to it because it returns 6 strings (one for each locale - // category), i.e. for C locale we get back "C C C C C C" - // - // this contradicts IBM own docs but this is not of much help, so just work around - // it in the crudest possible manner - wxChar *p = wxStrchr((wxChar *)retloc, _T(' ')); - if ( p ) - *p = _T('\0'); -#endif // __AIX__ - + const wxString langOnly = locale.Left(2); if ( !retloc ) { // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocaleTryUTF(LC_ALL, locale.Mid(0,2)); + retloc = wxSetlocaleTryUTF(LC_ALL, langOnly); } + +#if wxUSE_FONTMAP + // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but + // require the full xx_YY.encoding form, so try using UTF-8 because this is + // the only thing we can do generically + // + // TODO: add encodings applicable to each language to the lang DB and try + // them all in turn here if ( !retloc ) { - // Some C libraries (namely glibc) still use old ISO 639, - // so will translate the abbrev for them - wxString mid = locale.Mid(0,2); - if (mid == wxT("he")) - locale = wxT("iw") + locale.Mid(3); - else if (mid == wxT("id")) - locale = wxT("in") + locale.Mid(3); - else if (mid == wxT("yi")) - locale = wxT("ji") + locale.Mid(3); - else if (mid == wxT("nb")) - locale = wxT("no_NO"); - else if (mid == wxT("nn")) - locale = wxT("no_NY"); - - retloc = wxSetlocaleTryUTF(LC_ALL, locale); + const wxChar **names = + wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); + while ( *names ) + { + retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++); + if ( retloc ) + break; + } } +#endif // wxUSE_FONTMAP + if ( !retloc ) { - // (This time, we changed locale in previous if-branch, so try again.) - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocaleTryUTF(LC_ALL, locale.Mid(0,2)); + // Some C libraries (namely glibc) still use old ISO 639, + // so will translate the abbrev for them + wxString localeAlt; + if ( langOnly == wxT("he") ) + localeAlt = wxT("iw") + locale.Mid(3); + else if ( langOnly == wxT("id") ) + localeAlt = wxT("in") + locale.Mid(3); + else if ( langOnly == wxT("yi") ) + localeAlt = wxT("ji") + locale.Mid(3); + else if ( langOnly == wxT("nb") ) + localeAlt = wxT("no_NO"); + else if ( langOnly == wxT("nn") ) + localeAlt = wxT("no_NY"); + + if ( !localeAlt.empty() ) + { + retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); + if ( !retloc ) + retloc = wxSetlocaleTryUTF(LC_ALL, locale.Left(2)); + } } + if ( !retloc ) { wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); return false; } + +#ifdef __AIX__ + // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL) + // can't be passed back to it because it returns 6 strings (one for each locale + // category), i.e. for C locale we get back "C C C C C C" + // + // this contradicts IBM own docs but this is not of much help, so just work around + // it in the crudest possible manner + wxChar *p = wxStrchr((wxChar *)retloc, _T(' ')); + if ( p ) + *p = _T('\0'); +#endif // __AIX__ + #elif defined(__WIN32__) #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) @@ -1762,16 +1851,15 @@ bool wxLocale::Init(int language, int flags) wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); return false; } -#elif defined(__WXPM__) - wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString); #else + wxUnusedVar(flags); return false; #define WX_NO_LOCALE_SUPPORT #endif #ifndef WX_NO_LOCALE_SUPPORT wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL; - bool ret = Init(name, canonical, retloc, + bool ret = Init(name, canonical, szLocale, (flags & wxLOCALE_LOAD_DEFAULT) != 0, (flags & wxLOCALE_CONV_ENCODING) != 0); free(szLocale); @@ -1780,16 +1868,16 @@ bool wxLocale::Init(int language, int flags) m_language = lang; return ret; -#endif +#endif // !WX_NO_LOCALE_SUPPORT } void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) { - if ( s_searchPrefixes.Index(prefix) == wxNOT_FOUND ) + if ( gs_searchPrefixes.Index(prefix) == wxNOT_FOUND ) { - s_searchPrefixes.Add(prefix); + gs_searchPrefixes.Add(prefix); } //else: already have it } @@ -2364,7 +2452,7 @@ wxFontEncoding wxLocale::GetSystemEncoding() // on some modern Linux systems (RedHat 8) the default system locale // is UTF8 -- but it isn't supported by wxGTK in ANSI build at all so // don't even try to use it in this case -#if !wxUSE_UNICODE && defined(__WXGTK__) +#if !wxUSE_UNICODE && (defined(__WXGTK__) || defined(__WXMOTIF__)) if ( enc == wxFONTENCODING_UTF8 ) { // the most similar supported encoding... @@ -3545,4 +3633,3 @@ void wxLocale::InitLanguagesDB() // --- --- --- generated code ends here --- --- --- #endif // wxUSE_INTL -