Add AddAvailableCatalog() and use it in AddStdCatalog()
The new function only returns true if the catalog could be really loaded and not if it is considered not to be needed because the message ID language (which is typically "en-US") happens to be present in the preferred UI languages list (which seems to always include "en-US" in at least Western European MSW). This allows to distinguish, albeit in a rather awkward (but backwards-compatible) way between having a translation for the given language and not needed such translation. It is still not clear if it is really correct to return "en-US" from the list of preferred languages even if the user has never intentionally configured the OS to indicate that English is acceptable, but at least now we can work around this issue and use AddAvailableCatalog() in AddStdCatalog() to make sure we only skip loading unversioned wxstd.mo if the versioned wxstd-x.y.mo file is really found instead of never doing it, as was the case until now (see #23886). Also add GetBestAvailableTranslation() helper which seems more useful than the existing GetBestTranslation() one and is similarly related to it. See #18227, #23930. (cherry picked from commit 94b1a17aeb12a1ec723a255089be16cd31a268a2)
This commit is contained in:
parent
cbf081db91
commit
d178223745
@ -237,6 +237,7 @@ Changes in behaviour which may result in build errors
|
|||||||
|
|
||||||
All:
|
All:
|
||||||
|
|
||||||
|
- Fix wxTranslations::AddStdCatalog() and add AddAvailableCatalog() (#18227).
|
||||||
- Add move ctor and assignment operator to wxString (Pavel Tyunin, #23224).
|
- Add move ctor and assignment operator to wxString (Pavel Tyunin, #23224).
|
||||||
- Enable large file support in Unix CMake builds (Maarten Bent, #22750).
|
- Enable large file support in Unix CMake builds (Maarten Bent, #22750).
|
||||||
- Make wxSocket::Peek() work with UDP too (Brian Nixon, #23594, #23604).
|
- Make wxSocket::Peek() work with UDP too (Brian Nixon, #23594, #23604).
|
||||||
|
@ -154,16 +154,28 @@ public:
|
|||||||
// get languages available for this app
|
// get languages available for this app
|
||||||
wxArrayString GetAvailableTranslations(const wxString& domain) const;
|
wxArrayString GetAvailableTranslations(const wxString& domain) const;
|
||||||
|
|
||||||
// find best translation language for given domain
|
#if wxABI_VERSION >= 30203
|
||||||
|
// find best available translation language for given domain
|
||||||
|
wxString GetBestAvailableTranslation(const wxString& domain);
|
||||||
|
#endif // wxABI_VERSION >= 3.2.3
|
||||||
|
|
||||||
wxString GetBestTranslation(const wxString& domain, wxLanguage msgIdLanguage);
|
wxString GetBestTranslation(const wxString& domain, wxLanguage msgIdLanguage);
|
||||||
wxString GetBestTranslation(const wxString& domain,
|
wxString GetBestTranslation(const wxString& domain,
|
||||||
const wxString& msgIdLanguage = wxASCII_STR("en"));
|
const wxString& msgIdLanguage = wxASCII_STR("en"));
|
||||||
|
|
||||||
|
#if wxABI_VERSION >= 30203
|
||||||
|
// add catalog for the given domain returning true if it could be found by
|
||||||
|
// wxTranslationsLoader
|
||||||
|
bool AddAvailableCatalog(const wxString& domain);
|
||||||
|
#endif // wxABI_VERSION >= 3.2.3
|
||||||
|
|
||||||
// add standard wxWidgets catalog ("wxstd")
|
// add standard wxWidgets catalog ("wxstd")
|
||||||
bool AddStdCatalog();
|
bool AddStdCatalog();
|
||||||
|
|
||||||
// add catalog with given domain name and language, looking it up via
|
// add catalog with given domain name and language, looking it up via
|
||||||
// wxTranslationsLoader
|
// wxTranslationsLoader -- unlike AddAvailableCatalog(), this function also
|
||||||
|
// returns true if this catalog is not needed at all because msgIdLanguage
|
||||||
|
// is an acceptable language to use directly
|
||||||
bool AddCatalog(const wxString& domain,
|
bool AddCatalog(const wxString& domain,
|
||||||
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
|
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
|
||||||
#if !wxUSE_UNICODE
|
#if !wxUSE_UNICODE
|
||||||
|
@ -89,6 +89,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
wxArrayString GetAvailableTranslations(const wxString& domain) const;
|
wxArrayString GetAvailableTranslations(const wxString& domain) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the best available translation for the required language.
|
||||||
|
|
||||||
|
For wxLANGUAGE_DEFAULT, this function returns the available translation
|
||||||
|
best matching one of wxUILocale::GetPreferredUILanguages(). Otherwise
|
||||||
|
it simply returns the language set with SetLanguage() if it's available
|
||||||
|
or empty string otherwise.
|
||||||
|
|
||||||
|
@since 3.2.3
|
||||||
|
*/
|
||||||
|
wxString GetBestAvailableTranslation(const wxString& domain);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the best UI language for the @a domain.
|
Returns the best UI language for the @a domain.
|
||||||
|
|
||||||
@ -98,6 +110,13 @@ public:
|
|||||||
wxLocale::GetSystemLanguage(); modern operation systems (Windows
|
wxLocale::GetSystemLanguage(); modern operation systems (Windows
|
||||||
Vista+, macOS) have separate language and regional (= locale) settings.
|
Vista+, macOS) have separate language and regional (= locale) settings.
|
||||||
|
|
||||||
|
Please note that that this function may return the language
|
||||||
|
corresponding to @a msgIdLanguage if this language is considered to be
|
||||||
|
acceptable, i.e. is part of wxUILocale::GetPreferredUILanguages(),
|
||||||
|
indicating that it is fine not to use translations at all on this
|
||||||
|
system. If this is undesirable, GetBestAvailableTranslation() should be
|
||||||
|
used which doesn't consider the messages ID language as being available.
|
||||||
|
|
||||||
@param domain
|
@param domain
|
||||||
The catalog domain to look for.
|
The catalog domain to look for.
|
||||||
|
|
||||||
@ -142,14 +161,14 @@ public:
|
|||||||
|
|
||||||
@return @true if a suitable catalog was found, @false otherwise
|
@return @true if a suitable catalog was found, @false otherwise
|
||||||
|
|
||||||
@see AddCatalog()
|
@see AddAvailableCatalog()
|
||||||
*/
|
*/
|
||||||
bool AddStdCatalog();
|
bool AddStdCatalog();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Add a catalog for use with the current locale.
|
Add a catalog for use with the current locale.
|
||||||
|
|
||||||
By default, it is searched for in standard places (see
|
By default, the catalog is searched for in standard places (see
|
||||||
wxFileTranslationsLoader), but you may also prepend additional
|
wxFileTranslationsLoader), but you may also prepend additional
|
||||||
directories to the search path with
|
directories to the search path with
|
||||||
wxFileTranslationsLoader::AddCatalogLookupPathPrefix().
|
wxFileTranslationsLoader::AddCatalogLookupPathPrefix().
|
||||||
@ -157,6 +176,28 @@ public:
|
|||||||
All loaded catalogs will be used for message lookup by GetString() for
|
All loaded catalogs will be used for message lookup by GetString() for
|
||||||
the current locale.
|
the current locale.
|
||||||
|
|
||||||
|
@return
|
||||||
|
@true if catalog was successfully loaded, @false otherwise, usually
|
||||||
|
because it wasn't found. Note that unlike AddCatalog() this
|
||||||
|
function returns @false even if the language of the original
|
||||||
|
strings (usually English) can be used directly, i.e. its return
|
||||||
|
value only indicates that there are no catalogs available for the
|
||||||
|
selected or system-default languages, but is not necessarily an
|
||||||
|
error if no translations are needed in the first place.
|
||||||
|
|
||||||
|
@since 3.2.3
|
||||||
|
*/
|
||||||
|
bool AddAvailableCatalog(const wxString& domain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add a catalog for use with the current locale or fall back to the
|
||||||
|
original messages language.
|
||||||
|
|
||||||
|
This function behaves like AddAvailableCatalog() but also checks if the
|
||||||
|
strings used in the program, written in @a msgIdLanguage, can be used
|
||||||
|
without any translations on the current system and also returns @true
|
||||||
|
in this case, unlike AddAvailableCatalog().
|
||||||
|
|
||||||
By default, i.e. if @a msgIdLanguage is not given, @c msgid strings are assumed
|
By default, i.e. if @a msgIdLanguage is not given, @c msgid strings are assumed
|
||||||
to be in English and written only using 7-bit ASCII characters.
|
to be in English and written only using 7-bit ASCII characters.
|
||||||
If you have to deal with non-English strings or 8-bit characters in the
|
If you have to deal with non-English strings or 8-bit characters in the
|
||||||
@ -173,8 +214,10 @@ public:
|
|||||||
code are used instead.
|
code are used instead.
|
||||||
|
|
||||||
@return
|
@return
|
||||||
@true if catalog was successfully loaded, @false otherwise (which might
|
@true if catalog was successfully loaded or loading it is
|
||||||
mean that the catalog is not found or that it isn't in the correct format).
|
unnecessary because the original messages can be used directly,
|
||||||
|
@false otherwise (which might mean that the catalog is not found or
|
||||||
|
that it isn't in the correct format).
|
||||||
*/
|
*/
|
||||||
bool AddCatalog(const wxString& domain,
|
bool AddCatalog(const wxString& domain,
|
||||||
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
|
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
|
||||||
@ -213,7 +256,7 @@ public:
|
|||||||
According to GNU gettext tradition, each catalog normally corresponds to
|
According to GNU gettext tradition, each catalog normally corresponds to
|
||||||
'domain' which is more or less the application name.
|
'domain' which is more or less the application name.
|
||||||
|
|
||||||
@see AddCatalog()
|
@see AddAvailableCatalog()
|
||||||
*/
|
*/
|
||||||
bool IsLoaded(const wxString& domain) const;
|
bool IsLoaded(const wxString& domain) const;
|
||||||
|
|
||||||
@ -348,7 +391,7 @@ public:
|
|||||||
(in this order).
|
(in this order).
|
||||||
|
|
||||||
This only applies to subsequent invocations of
|
This only applies to subsequent invocations of
|
||||||
wxTranslations::AddCatalog().
|
wxTranslations::AddAvailableCatalog().
|
||||||
*/
|
*/
|
||||||
static void AddCatalogLookupPathPrefix(const wxString& prefix);
|
static void AddCatalogLookupPathPrefix(const wxString& prefix);
|
||||||
};
|
};
|
||||||
@ -358,8 +401,7 @@ public:
|
|||||||
resources.
|
resources.
|
||||||
|
|
||||||
If you wish to store translation MO files in resources, you have to
|
If you wish to store translation MO files in resources, you have to
|
||||||
enable this loader before calling wxTranslations::AddCatalog() or
|
enable this loader before calling wxTranslations::AddAvailableCatalog():
|
||||||
wxLocale::AddCatalog():
|
|
||||||
|
|
||||||
@code
|
@code
|
||||||
wxTranslations::Get()->SetLoader(new wxResourceTranslationsLoader);
|
wxTranslations::Get()->SetLoader(new wxResourceTranslationsLoader);
|
||||||
|
@ -1406,7 +1406,7 @@ bool wxTranslations::AddStdCatalog()
|
|||||||
// the name without the version if it's not found, as message catalogs
|
// the name without the version if it's not found, as message catalogs
|
||||||
// typically won't have the version in their names under non-Unix platforms
|
// typically won't have the version in their names under non-Unix platforms
|
||||||
// (i.e. where they're not installed by our own "make install").
|
// (i.e. where they're not installed by our own "make install").
|
||||||
if ( AddCatalog("wxstd-" wxSTRINGIZE(wxMAJOR_VERSION) "." wxSTRINGIZE(wxMINOR_VERSION)) )
|
if ( AddAvailableCatalog("wxstd-" wxSTRINGIZE(wxMAJOR_VERSION) "." wxSTRINGIZE(wxMINOR_VERSION)) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if ( AddCatalog(wxS("wxstd")) )
|
if ( AddCatalog(wxS("wxstd")) )
|
||||||
@ -1425,12 +1425,9 @@ bool wxTranslations::AddCatalog(const wxString& domain,
|
|||||||
}
|
}
|
||||||
#endif // !wxUSE_UNICODE
|
#endif // !wxUSE_UNICODE
|
||||||
|
|
||||||
bool wxTranslations::AddCatalog(const wxString& domain,
|
bool wxTranslations::AddAvailableCatalog(const wxString& domain)
|
||||||
wxLanguage msgIdLanguage)
|
|
||||||
{
|
{
|
||||||
const wxString msgIdLang = wxUILocale::GetLanguageCanonicalName(msgIdLanguage);
|
const wxString domain_lang = GetBestAvailableTranslation(domain);
|
||||||
const wxString domain_lang = GetBestTranslation(domain, msgIdLang);
|
|
||||||
|
|
||||||
if ( domain_lang.empty() )
|
if ( domain_lang.empty() )
|
||||||
{
|
{
|
||||||
wxLogTrace(TRACE_I18N,
|
wxLogTrace(TRACE_I18N,
|
||||||
@ -1439,11 +1436,27 @@ bool wxTranslations::AddCatalog(const wxString& domain,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLogTrace(TRACE_I18N,
|
return LoadCatalog(domain, domain_lang, wxString());
|
||||||
wxS("adding '%s' translation for domain '%s' (msgid language '%s')"),
|
}
|
||||||
domain_lang, domain, msgIdLang);
|
|
||||||
|
|
||||||
return LoadCatalog(domain, domain_lang, msgIdLang);
|
bool wxTranslations::AddCatalog(const wxString& domain,
|
||||||
|
wxLanguage msgIdLanguage)
|
||||||
|
{
|
||||||
|
if ( AddAvailableCatalog(domain) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const wxString msgIdLang = wxUILocale::GetLanguageCanonicalName(msgIdLanguage);
|
||||||
|
const wxString domain_lang = GetBestTranslation(domain, msgIdLang);
|
||||||
|
|
||||||
|
if ( msgIdLang == domain_lang )
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_I18N,
|
||||||
|
wxS("not using translations for domain '%s' with msgid language '%s'"),
|
||||||
|
domain, msgIdLang);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1451,6 +1464,12 @@ bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang, c
|
|||||||
{
|
{
|
||||||
wxCHECK_MSG( m_loader, false, "loader can't be NULL" );
|
wxCHECK_MSG( m_loader, false, "loader can't be NULL" );
|
||||||
|
|
||||||
|
// This parameter is kept for ABI compatibility (this function is private,
|
||||||
|
// but the automated ABI check still fails if its signature is modified)
|
||||||
|
// but not used any longer because the case of domain being equal to
|
||||||
|
// msgIdLang is checked in AddCatalog() now.
|
||||||
|
wxUnusedVar(msgIdLang);
|
||||||
|
|
||||||
wxMsgCatalog *cat = NULL;
|
wxMsgCatalog *cat = NULL;
|
||||||
|
|
||||||
#if wxUSE_FONTMAP
|
#if wxUSE_FONTMAP
|
||||||
@ -1484,15 +1503,6 @@ bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang, c
|
|||||||
cat = m_loader->LoadCatalog(domain, baselang);
|
cat = m_loader->LoadCatalog(domain, baselang);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !cat )
|
|
||||||
{
|
|
||||||
// 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 ( msgIdLang == lang )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( cat )
|
if ( cat )
|
||||||
{
|
{
|
||||||
// add it to the head of the list so that in GetString it will
|
// add it to the head of the list so that in GetString it will
|
||||||
@ -1530,14 +1540,56 @@ wxString wxTranslations::GetBestTranslation(const wxString& domain,
|
|||||||
wxString wxTranslations::GetBestTranslation(const wxString& domain,
|
wxString wxTranslations::GetBestTranslation(const wxString& domain,
|
||||||
const wxString& msgIdLanguage)
|
const wxString& msgIdLanguage)
|
||||||
{
|
{
|
||||||
// explicitly set language should always be respected
|
wxString lang = GetBestAvailableTranslation(domain);
|
||||||
if ( !m_lang.empty() )
|
if ( lang.empty() )
|
||||||
return m_lang;
|
{
|
||||||
|
wxArrayString available;
|
||||||
|
available.push_back(msgIdLanguage);
|
||||||
|
available.push_back(msgIdLanguage.BeforeFirst('_'));
|
||||||
|
lang = GetPreferredUILanguage(available);
|
||||||
|
if ( lang.empty() )
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_I18N,
|
||||||
|
"no available language for domain '%s'", domain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_I18N,
|
||||||
|
"using message ID language '%s' for domain '%s'", lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wxArrayString available(GetAvailableTranslations(domain));
|
return lang;
|
||||||
// it's OK to have duplicates, so just add msgid language
|
}
|
||||||
available.push_back(msgIdLanguage);
|
|
||||||
available.push_back(msgIdLanguage.BeforeFirst('_'));
|
wxString wxTranslations::GetBestAvailableTranslation(const wxString& domain)
|
||||||
|
{
|
||||||
|
const wxArrayString available(GetAvailableTranslations(domain));
|
||||||
|
if ( !m_lang.empty() )
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_I18N,
|
||||||
|
"searching for best translation to %s for domain '%s'",
|
||||||
|
m_lang, domain);
|
||||||
|
|
||||||
|
wxString lang;
|
||||||
|
if ( available.Index(m_lang) != wxNOT_FOUND )
|
||||||
|
{
|
||||||
|
lang = m_lang;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const wxString baselang = m_lang.BeforeFirst('_');
|
||||||
|
if ( baselang != m_lang && available.Index(baselang) != wxNOT_FOUND )
|
||||||
|
lang = baselang;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( lang.empty() )
|
||||||
|
wxLogTrace(TRACE_I18N, " => no available translations found");
|
||||||
|
else
|
||||||
|
wxLogTrace(TRACE_I18N, " => found '%s'", lang);
|
||||||
|
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
|
||||||
wxLogTrace(TRACE_I18N, "choosing best language for domain '%s'", domain);
|
wxLogTrace(TRACE_I18N, "choosing best language for domain '%s'", domain);
|
||||||
LogTraceArray(" - available translations", available);
|
LogTraceArray(" - available translations", available);
|
||||||
|
@ -237,6 +237,39 @@ void IntlTestCase::IsAvailable()
|
|||||||
CPPUNIT_ASSERT_EQUAL( origLocale, setlocale(LC_ALL, NULL) );
|
CPPUNIT_ASSERT_EQUAL( origLocale, setlocale(LC_ALL, NULL) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("wxTranslations::Available", "[translations]")
|
||||||
|
{
|
||||||
|
// We currently have translations for French and Japanese in this test
|
||||||
|
// directory, check that loading those succeeds but loading others doesn't.
|
||||||
|
wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
|
||||||
|
|
||||||
|
const wxString domain("internat");
|
||||||
|
|
||||||
|
wxTranslations trans;
|
||||||
|
|
||||||
|
SECTION("All")
|
||||||
|
{
|
||||||
|
wxArrayString available = trans.GetAvailableTranslations(domain);
|
||||||
|
REQUIRE( available.size() == 2 );
|
||||||
|
|
||||||
|
available.Sort();
|
||||||
|
CHECK( available[0] == "fr" );
|
||||||
|
CHECK( available[1] == "ja" );
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("French")
|
||||||
|
{
|
||||||
|
trans.SetLanguage(wxLANGUAGE_FRENCH);
|
||||||
|
CHECK( trans.AddAvailableCatalog(domain) );
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Italian")
|
||||||
|
{
|
||||||
|
trans.SetLanguage(wxLANGUAGE_ITALIAN);
|
||||||
|
CHECK_FALSE( trans.AddAvailableCatalog(domain) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The test may fail in ANSI builds because of unsupported encoding, but we
|
// The test may fail in ANSI builds because of unsupported encoding, but we
|
||||||
// don't really care about this build anyhow, so just skip it there.
|
// don't really care about this build anyhow, so just skip it there.
|
||||||
#if wxUSE_UNICODE
|
#if wxUSE_UNICODE
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
extern "C++" {
|
extern "C++" {
|
||||||
"wxGLCanvasEGL::CreateWaylandSubsurface";
|
"wxGLCanvasEGL::CreateWaylandSubsurface";
|
||||||
"wxGLCanvasEGL::DestroyWaylandSubsurface";
|
"wxGLCanvasEGL::DestroyWaylandSubsurface";
|
||||||
|
"wxTranslations::AddAvailableCatalog";
|
||||||
|
"wxTranslations::GetBestAvailableTranslation";
|
||||||
"wxUILocale::GetMonthName";
|
"wxUILocale::GetMonthName";
|
||||||
"wxUILocale::GetWeekDayName";
|
"wxUILocale::GetWeekDayName";
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user