Support creating Unix wxUILocale for languages without region
Unlike MSW and macOS, creating wxUILocale for e.g. "en" doesn't necessarily succeed under Linux even if "en_US" is available, so try to find a working language+region combination if just language doesn't work. This requires access to the languages database, so add a private wxGetLanguageInfos() to avoid having to depend on wxLocale just for this.
This commit is contained in:
@@ -12,6 +12,12 @@
|
||||
|
||||
#include "wx/localedefs.h"
|
||||
#include "wx/string.h"
|
||||
#include "wx/vector.h"
|
||||
|
||||
typedef wxVector<wxLanguageInfo> wxLanguageInfos;
|
||||
|
||||
// Return the vector of all known languages.
|
||||
const wxLanguageInfos& wxGetLanguageInfos();
|
||||
|
||||
// Function returning hard-coded values for the "C" locale.
|
||||
wxString wxGetStdCLocaleInfo(wxLocaleInfo index, wxLocaleCategory cat);
|
||||
|
@@ -51,7 +51,8 @@
|
||||
#include "wx/stdpaths.h"
|
||||
#include "wx/hashset.h"
|
||||
#include "wx/uilocale.h"
|
||||
#include "wx/vector.h"
|
||||
|
||||
#include "wx/private/uilocale.h"
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include "wx/msw/private/uilocale.h"
|
||||
@@ -193,9 +194,16 @@ wxString wxLanguageInfo::GetLocaleName() const
|
||||
// wxLocale
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static wxVector<wxLanguageInfo> gs_languagesDB;
|
||||
static wxLanguageInfos gs_languagesDB;
|
||||
static bool gs_languagesDBInitialized = false;
|
||||
|
||||
const wxLanguageInfos& wxGetLanguageInfos()
|
||||
{
|
||||
wxLocale::CreateLanguagesDB();
|
||||
|
||||
return gs_languagesDB;
|
||||
}
|
||||
|
||||
/*static*/ void wxLocale::CreateLanguagesDB()
|
||||
{
|
||||
if (!gs_languagesDBInitialized)
|
||||
|
@@ -80,6 +80,22 @@ inline locale_t TryCreateLocale(const wxLocaleIdent& locId)
|
||||
return newlocale(LC_ALL_MASK, locId.GetName().mb_str(), NULL);
|
||||
}
|
||||
|
||||
// Wrapper around newlocale() also trying to append UTF-8 codeset (and
|
||||
// modifying its wxLocaleIdent argument if it succeeds).
|
||||
locale_t TryCreateLocaleWithUTF8(wxLocaleIdent& locId)
|
||||
{
|
||||
locale_t loc = TryCreateLocale(locId);
|
||||
if ( !loc && locId.GetCharset().empty() )
|
||||
{
|
||||
wxLocaleIdent locIdUTF8 = wxLocaleIdent(locId).Charset("UTF-8");
|
||||
loc = TryCreateLocale(locIdUTF8);
|
||||
if ( loc )
|
||||
locId = locIdUTF8;
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
#endif // HAVE_LOCALE_T
|
||||
|
||||
} // anonymous namespace
|
||||
@@ -337,7 +353,7 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLocale(const wxLocaleIdent& locIdOrig)
|
||||
// Make a copy of it because it can be modified below.
|
||||
wxLocaleIdent locId = locIdOrig;
|
||||
|
||||
locale_t loc = TryCreateLocale(locId);
|
||||
locale_t loc = TryCreateLocaleWithUTF8(locId);
|
||||
if ( !loc )
|
||||
{
|
||||
// Try to find a variant of this locale available on this system: first
|
||||
@@ -345,28 +361,38 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLocale(const wxLocaleIdent& locIdOrig)
|
||||
// does _not_ work under Linux, so try adding one if we don't have it.
|
||||
if ( locId.GetRegion().empty() )
|
||||
{
|
||||
const wxLanguageInfo* const info =
|
||||
wxLocale::FindLanguageInfo(locId.GetLanguage());
|
||||
if ( info )
|
||||
const wxString lang = locId.GetLanguage();
|
||||
|
||||
const wxLanguageInfos& infos = wxGetLanguageInfos();
|
||||
for ( wxLanguageInfos::const_iterator it = infos.begin();
|
||||
it != infos.end();
|
||||
++it )
|
||||
{
|
||||
wxString region = info->CanonicalName.AfterFirst('_');
|
||||
if ( !region.empty() )
|
||||
const wxString& fullname = it->CanonicalName;
|
||||
if ( fullname.BeforeFirst('_') == lang )
|
||||
{
|
||||
// We never have encoding in our canonical names, but we
|
||||
// can have modifiers, so get rid of them if necessary.
|
||||
region = region.BeforeFirst('@');
|
||||
const wxString&
|
||||
region = fullname.AfterFirst('_').BeforeFirst('@');
|
||||
if ( !region.empty() )
|
||||
{
|
||||
loc = TryCreateLocaleWithUTF8(locId.Region(region));
|
||||
if ( loc )
|
||||
{
|
||||
// We take the first available region, we don't
|
||||
// have enough data to know how to prioritize them
|
||||
// (and wouldn't want to start any geopolitical
|
||||
// disputes).
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loc = TryCreateLocale(locId.Region(region));
|
||||
// Don't bother reverting region to the old value as it will
|
||||
// be overwritten during the next loop iteration anyhow.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And sometimes the locale without encoding is not available, but one
|
||||
// with UTF-8 encoding is, so try this too.
|
||||
if ( !loc && locId.GetCharset().empty() )
|
||||
{
|
||||
loc = TryCreateLocale(locId.Charset("UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
if ( !loc )
|
||||
|
Reference in New Issue
Block a user