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:
Vadim Zeitlin
2021-09-01 01:02:00 +02:00
parent e92da29272
commit 3f8fd90c31
3 changed files with 57 additions and 17 deletions

View File

@@ -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);

View File

@@ -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)

View File

@@ -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 )