X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ea14492351395f1dcea060e8db0860f865b92658..ba49d2acf95d53517719c4fd9ac2ad5aaa13540b:/src/common/intl.cpp diff --git a/src/common/intl.cpp b/src/common/intl.cpp index cc1377007f..a7aaf30597 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -79,11 +79,6 @@ // constants // ---------------------------------------------------------------------------- -// the constants describing the format of ll_CC locale string -static const size_t LEN_LANG = 2; -static const size_t LEN_SUBLANG = 2; -static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_' - #define TRACE_I18N wxS("i18n") // ============================================================================ @@ -99,10 +94,10 @@ static wxLocale *wxSetLocale(wxLocale *pLocale); namespace { -// get just the language part +// get just the language part ("en" in "en_GB") inline wxString ExtractLang(const wxString& langFull) { - return langFull.Left(LEN_LANG); + return langFull.BeforeFirst('_'); } // helper functions of GetSystemLanguage() @@ -111,7 +106,11 @@ inline wxString ExtractLang(const wxString& langFull) // get everything else (including the leading '_') inline wxString ExtractNotLang(const wxString& langFull) { - return langFull.Mid(LEN_LANG); + size_t pos = langFull.find('_'); + if ( pos != wxString::npos ) + return langFull.substr(pos); + else + return wxString(); } #endif // __UNIX__ @@ -122,7 +121,7 @@ inline wxString ExtractNotLang(const wxString& langFull) // wxLanguageInfo // ---------------------------------------------------------------------------- -#ifdef __WXMSW__ +#ifdef __WINDOWS__ // helper used by wxLanguageInfo::GetLocaleName() and elsewhere to determine // whether the locale is Unicode-only (it is if this function returns empty @@ -178,7 +177,7 @@ wxString wxLanguageInfo::GetLocaleName() const return locale; } -#endif // __WXMSW__ +#endif // __WINDOWS__ // ---------------------------------------------------------------------------- // wxLocale @@ -201,8 +200,7 @@ wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL; /*static*/ void wxLocale::DestroyLanguagesDB() { - delete ms_languagesDB; - ms_languagesDB = NULL; + wxDELETE(ms_languagesDB); } @@ -211,7 +209,24 @@ void wxLocale::DoCommonInit() m_pszOldLocale = NULL; m_pOldLocale = wxSetLocale(this); - wxTranslations::SetNonOwned(&m_translations); + + // Set translations object, but only if the user didn't do so yet. + // This is to preserve compatibility with wx-2.8 where wxLocale was + // the only API for translations. wxLocale works as a stack, with + // latest-created one being the active one: + // wxLocale loc_fr(wxLANGUAGE_FRENCH); + // // _() returns French + // { + // wxLocale loc_cs(wxLANGUAGE_CZECH); + // // _() returns Czech + // } + // // _() returns French again + wxTranslations *oldTrans = wxTranslations::Get(); + if ( !oldTrans || + (m_pOldLocale && oldTrans == &m_pOldLocale->m_translations) ) + { + wxTranslations::SetNonOwned(&m_translations); + } m_language = wxLANGUAGE_UNKNOWN; m_initialized = false; @@ -223,7 +238,7 @@ bool wxLocale::Init(const wxString& name, const wxString& locale, bool bLoadDefault #if WXWIN_COMPATIBILITY_2_8 - ,bool bConvertEncoding + ,bool WXUNUSED_UNLESS_DEBUG(bConvertEncoding) #endif ) { @@ -235,10 +250,14 @@ bool wxLocale::Init(const wxString& name, bool ret = DoInit(name, shortName, locale); // NB: don't use 'lang' here, 'language' may be wxLANGUAGE_DEFAULT - m_translations.SetLanguage(shortName); + wxTranslations *t = wxTranslations::Get(); + if ( t ) + { + t->SetLanguage(shortName); - if ( bLoadDefault ) - m_translations.AddStdCatalog(); + if ( bLoadDefault ) + t->AddStdCatalog(); + } return ret; } @@ -274,7 +293,7 @@ bool wxLocale::DoInit(const wxString& name, if ( m_pszOldLocale == NULL ) { - wxLogError(_("locale '%s' can not be set."), szLocale); + wxLogError(_("locale '%s' cannot be set."), szLocale); } // the short name will be used to look for catalog files as well, @@ -538,10 +557,14 @@ bool wxLocale::Init(int language, int flags) m_language = lang; // NB: don't use 'lang' here, 'language' - m_translations.SetLanguage(wx_static_cast(wxLanguage, language)); + wxTranslations *t = wxTranslations::Get(); + if ( t ) + { + t->SetLanguage(static_cast(language)); - if ( flags & wxLOCALE_LOAD_DEFAULT ) - m_translations.AddStdCatalog(); + if ( flags & wxLOCALE_LOAD_DEFAULT ) + t->AddStdCatalog(); + } return ret; #endif // !WX_NO_LOCALE_SUPPORT @@ -617,94 +640,92 @@ bool wxLocale::Init(int language, int flags) 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 - // check for this - // do we have just the language (or sublang too)? - bool justLang = langFull.length() == LEN_LANG; - if ( justLang || - (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxS('_')) ) - { - // 0. Make sure the lang is according to latest ISO 639 - // (this is necessary because glibc uses iw and in instead - // of he and id respectively). - - // the language itself (second part is the dialect/sublang) - wxString langOrig = ExtractLang(langFull); - - wxString lang; - if ( langOrig == wxS("iw")) - lang = wxS("he"); - else if (langOrig == wxS("in")) - lang = wxS("id"); - else if (langOrig == wxS("ji")) - lang = wxS("yi"); - else if (langOrig == wxS("no_NO")) - lang = wxS("nb_NO"); - else if (langOrig == wxS("no_NY")) - lang = wxS("nn_NO"); - else if (langOrig == wxS("no")) - lang = wxS("nb_NO"); - else - lang = langOrig; + const bool justLang = langFull.find('_') == wxString::npos; + + // 0. Make sure the lang is according to latest ISO 639 + // (this is necessary because glibc uses iw and in instead + // of he and id respectively). + + // the language itself (second part is the dialect/sublang) + wxString langOrig = ExtractLang(langFull); + + wxString lang; + if ( langOrig == wxS("iw")) + lang = wxS("he"); + else if (langOrig == wxS("in")) + lang = wxS("id"); + else if (langOrig == wxS("ji")) + lang = wxS("yi"); + else if (langOrig == wxS("no_NO")) + lang = wxS("nb_NO"); + else if (langOrig == wxS("no_NY")) + lang = wxS("nn_NO"); + else if (langOrig == wxS("no")) + lang = wxS("nb_NO"); + else + lang = langOrig; - // did we change it? - if ( lang != langOrig ) - { - langFull = lang + ExtractNotLang(langFull); - } + // did we change it? + if ( lang != langOrig ) + { + langFull = lang + ExtractNotLang(langFull); + } - // 1. Try to find the language either as is: - // a) With modifier if set - if ( !modifier.empty() ) + // 1. Try to find the language either as is: + // a) With modifier if set + if ( !modifier.empty() ) + { + wxString langFullWithModifier = langFull + modifier; + for ( i = 0; i < count; i++ ) { - wxString langFullWithModifier = langFull + modifier; - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) - break; - } + if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) + break; } + } - // b) Without modifier - if ( modifier.empty() || i == count ) + // b) Without modifier + if ( modifier.empty() || i == count ) + { + for ( i = 0; i < count; i++ ) { - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == langFull ) - break; - } + if ( ms_languagesDB->Item(i).CanonicalName == langFull ) + break; } + } - // 2. If langFull is of the form xx_YY, try to find xx: - if ( i == count && !justLang ) + // 2. If langFull is of the form xx_YY, try to find xx: + if ( i == count && !justLang ) + { + for ( i = 0; i < count; i++ ) { - for ( i = 0; i < count; i++ ) + if ( ms_languagesDB->Item(i).CanonicalName == lang ) { - if ( ms_languagesDB->Item(i).CanonicalName == lang ) - { - break; - } + break; } } + } - // 3. If langFull is of the form xx, try to find any xx_YY record: - if ( i == count && justLang ) + // 3. If langFull is of the form xx, try to find any xx_YY record: + if ( i == count && justLang ) + { + for ( i = 0; i < count; i++ ) { - for ( i = 0; i < count; i++ ) + if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) + == langFull ) { - if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) - == langFull ) - { - break; - } + break; } } } - else // not standard format + + + if ( i == count ) { - // try to find the name in verbose description + // 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 check for use of non-standard format and try to + // find the name in verbose description. for ( i = 0; i < count; i++ ) { if (ms_languagesDB->Item(i).Description.CmpNoCase(langFull) == 0) @@ -760,8 +781,9 @@ wxString wxLocale::GetSystemEncodingName() UINT codepage = ::GetACP(); encname.Printf(wxS("windows-%u"), codepage); #elif defined(__WXMAC__) - // default is just empty string, this resolves to the default system - // encoding later + encname = wxCFStringRef::AsString( + CFStringGetNameOfEncoding(CFStringGetSystemEncoding()) + ); #elif defined(__UNIX_LIKE__) #if defined(HAVE_LANGINFO_H) && defined(CODESET) @@ -988,7 +1010,9 @@ wxString wxLocale::GetSysName() const // clean up wxLocale::~wxLocale() { - // restore old translations object + // Restore old translations object. + // See DoCommonInit() for explanation of why this is needed for backward + // compatibility. if ( wxTranslations::Get() == &m_translations ) { if ( m_pOldLocale ) @@ -1001,7 +1025,7 @@ wxLocale::~wxLocale() wxSetLocale(m_pOldLocale); wxSetlocale(LC_ALL, m_pszOldLocale); - free((wxChar *)m_pszOldLocale); // const_cast + free(const_cast(m_pszOldLocale)); } @@ -1010,7 +1034,14 @@ wxLocale::~wxLocale() bool wxLocale::IsAvailable(int lang) { const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); - wxCHECK_MSG( info, false, wxS("invalid language") ); + if ( !info ) + { + // The language is unknown (this normally only happens when we're + // passed wxLANGUAGE_DEFAULT), so we can't support it. + wxASSERT_MSG( lang == wxLANGUAGE_DEFAULT, + wxS("No info for a valid language?") ); + return false; + } #if defined(__WIN32__) if ( !info->WinLang ) @@ -1022,39 +1053,81 @@ bool wxLocale::IsAvailable(int lang) #elif defined(__UNIX__) // Test if setting the locale works, then set it back. - const char *oldLocale = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName); - if ( !oldLocale ) - { - // Some C libraries don't like xx_YY form and require xx only - oldLocale = wxSetlocaleTryUTF8(LC_ALL, ExtractLang(info->CanonicalName)); - if ( !oldLocale ) - return false; - } + char * const oldLocale = wxStrdupA(setlocale(LC_ALL, NULL)); + + // Some platforms don't like xx_YY form and require xx only so test for + // it too. + const bool + available = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName) || + wxSetlocaleTryUTF8(LC_ALL, ExtractLang(info->CanonicalName)); + // restore the original locale wxSetlocale(LC_ALL, oldLocale); + + free(oldLocale); + + if ( !available ) + return false; #endif return true; } + +bool wxLocale::AddCatalog(const wxString& domain) +{ + wxTranslations *t = wxTranslations::Get(); + if ( !t ) + return false; + return t->AddCatalog(domain); +} + +bool wxLocale::AddCatalog(const wxString& domain, wxLanguage msgIdLanguage) +{ + wxTranslations *t = wxTranslations::Get(); + if ( !t ) + return false; + return t->AddCatalog(domain, msgIdLanguage); +} + // add a catalog to our linked list bool wxLocale::AddCatalog(const wxString& szDomain, wxLanguage msgIdLanguage, const wxString& msgIdCharset) { + wxTranslations *t = wxTranslations::Get(); + if ( !t ) + return false; #if wxUSE_UNICODE wxUnusedVar(msgIdCharset); - return m_translations.AddCatalog(szDomain, msgIdLanguage); + return t->AddCatalog(szDomain, msgIdLanguage); #else - return m_translations.AddCatalog(szDomain, msgIdLanguage, msgIdCharset); + return t->AddCatalog(szDomain, msgIdLanguage, msgIdCharset); #endif } +bool wxLocale::IsLoaded(const wxString& domain) const +{ + wxTranslations *t = wxTranslations::Get(); + if ( !t ) + return false; + return t->IsLoaded(domain); +} + +wxString wxLocale::GetHeaderValue(const wxString& header, + const wxString& domain) const +{ + wxTranslations *t = wxTranslations::Get(); + if ( !t ) + return wxEmptyString; + return t->GetHeaderValue(header, domain); +} + // ---------------------------------------------------------------------------- // accessors for locale-dependent data // ---------------------------------------------------------------------------- -#if defined(__WXMSW__) || defined(__WXOSX__) +#if defined(__WINDOWS__) || defined(__WXOSX__) namespace { @@ -1076,7 +1149,7 @@ static wxString TranslateFromUnicodeFormat(const wxString& fmt) const char* formatchars = "dghHmMsSy" -#ifdef __WXMSW__ +#ifdef __WINDOWS__ "t" #else "EawD" @@ -1116,7 +1189,7 @@ static wxString TranslateFromUnicodeFormat(const wxString& fmt) // between 1 and 2 digits for days fmtWX += "%d"; break; -#ifdef __WXMSW__ +#ifdef __WINDOWS__ case 3: // ddd fmtWX += "%a"; break; @@ -1129,7 +1202,7 @@ static wxString TranslateFromUnicodeFormat(const wxString& fmt) wxFAIL_MSG( "too many 'd's" ); } break; -#ifndef __WXMSW__ +#ifndef __WINDOWS__ case 'D': switch ( lastCount ) { @@ -1272,12 +1345,12 @@ static wxString TranslateFromUnicodeFormat(const wxString& fmt) wxASSERT_MSG( lastCount <= 2, "too many 'g's" ); break; -#ifndef __WXMSW__ +#ifndef __WINDOWS__ case 'a': fmtWX += "%p"; break; #endif -#ifdef __WXMSW__ +#ifdef __WINDOWS__ case 't': switch ( lastCount ) { @@ -1317,9 +1390,9 @@ static wxString TranslateFromUnicodeFormat(const wxString& fmt) } // anonymous namespace -#endif // __WXMSW__ || __WXOSX__ +#endif // __WINDOWS__ || __WXOSX__ -#if defined(__WXMSW__) +#if defined(__WINDOWS__) namespace { @@ -1347,7 +1420,7 @@ LCTYPE GetLCTYPEFormatFromLocalInfo(wxLocaleInfo index) } // anonymous namespace /* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) { wxUint32 lcid = LOCALE_USER_DEFAULT; if ( wxGetLocale() ) @@ -1365,9 +1438,35 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) switch ( index ) { + case wxLOCALE_THOUSANDS_SEP: + if ( ::GetLocaleInfo(lcid, LOCALE_STHOUSAND, buf, WXSIZEOF(buf)) ) + str = buf; + break; + case wxLOCALE_DECIMAL_POINT: - if ( ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buf, WXSIZEOF(buf)) ) + if ( ::GetLocaleInfo(lcid, + cat == wxLOCALE_CAT_MONEY + ? LOCALE_SMONDECIMALSEP + : LOCALE_SDECIMAL, + buf, + WXSIZEOF(buf)) ) + { str = buf; + + // As we get our decimal point separator from Win32 and not the + // CRT there is a possibility of mismatch between them and this + // can easily happen if the user code called setlocale() + // instead of using wxLocale to change the locale. And this can + // result in very strange bugs elsewhere in the code as the + // assumptions that formatted strings do use the decimal + // separator actually fail, so check for it here. + wxASSERT_MSG + ( + wxString::Format("%.3f", 1.23).find(str) != wxString::npos, + "Decimal separator mismatch -- did you use setlocale()?" + "If so, use wxLocale to change the locale instead." + ); + } break; case wxLOCALE_SHORT_DATE_FMT: @@ -1484,7 +1583,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) return str.AsString(); } -#else // !__WXMSW__ && !__WXOSX__, assume generic POSIX +#else // !__WINDOWS__ && !__WXOSX__, assume generic POSIX namespace {