Skip to content

Commit d178223

Browse files
committed
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 wxWidgets#23886). Also add GetBestAvailableTranslation() helper which seems more useful than the existing GetBestTranslation() one and is similarly related to it. See wxWidgets#18227, wxWidgets#23930. (cherry picked from commit 94b1a17)
1 parent cbf081d commit d178223

File tree

6 files changed

+177
-35
lines changed

6 files changed

+177
-35
lines changed

docs/changes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ Changes in behaviour which may result in build errors
237237

238238
All:
239239

240+
- Fix wxTranslations::AddStdCatalog() and add AddAvailableCatalog() (#18227).
240241
- Add move ctor and assignment operator to wxString (Pavel Tyunin, #23224).
241242
- Enable large file support in Unix CMake builds (Maarten Bent, #22750).
242243
- Make wxSocket::Peek() work with UDP too (Brian Nixon, #23594, #23604).

include/wx/translation.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,16 +154,28 @@ class WXDLLIMPEXP_BASE wxTranslations
154154
// get languages available for this app
155155
wxArrayString GetAvailableTranslations(const wxString& domain) const;
156156

157-
// find best translation language for given domain
157+
#if wxABI_VERSION >= 30203
158+
// find best available translation language for given domain
159+
wxString GetBestAvailableTranslation(const wxString& domain);
160+
#endif // wxABI_VERSION >= 3.2.3
161+
158162
wxString GetBestTranslation(const wxString& domain, wxLanguage msgIdLanguage);
159163
wxString GetBestTranslation(const wxString& domain,
160164
const wxString& msgIdLanguage = wxASCII_STR("en"));
161165

166+
#if wxABI_VERSION >= 30203
167+
// add catalog for the given domain returning true if it could be found by
168+
// wxTranslationsLoader
169+
bool AddAvailableCatalog(const wxString& domain);
170+
#endif // wxABI_VERSION >= 3.2.3
171+
162172
// add standard wxWidgets catalog ("wxstd")
163173
bool AddStdCatalog();
164174

165175
// add catalog with given domain name and language, looking it up via
166-
// wxTranslationsLoader
176+
// wxTranslationsLoader -- unlike AddAvailableCatalog(), this function also
177+
// returns true if this catalog is not needed at all because msgIdLanguage
178+
// is an acceptable language to use directly
167179
bool AddCatalog(const wxString& domain,
168180
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
169181
#if !wxUSE_UNICODE

interface/wx/translation.h

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ class wxTranslations
8989
*/
9090
wxArrayString GetAvailableTranslations(const wxString& domain) const;
9191

92+
/**
93+
Returns the best available translation for the required language.
94+
95+
For wxLANGUAGE_DEFAULT, this function returns the available translation
96+
best matching one of wxUILocale::GetPreferredUILanguages(). Otherwise
97+
it simply returns the language set with SetLanguage() if it's available
98+
or empty string otherwise.
99+
100+
@since 3.2.3
101+
*/
102+
wxString GetBestAvailableTranslation(const wxString& domain);
103+
92104
/**
93105
Returns the best UI language for the @a domain.
94106
@@ -98,6 +110,13 @@ class wxTranslations
98110
wxLocale::GetSystemLanguage(); modern operation systems (Windows
99111
Vista+, macOS) have separate language and regional (= locale) settings.
100112
113+
Please note that that this function may return the language
114+
corresponding to @a msgIdLanguage if this language is considered to be
115+
acceptable, i.e. is part of wxUILocale::GetPreferredUILanguages(),
116+
indicating that it is fine not to use translations at all on this
117+
system. If this is undesirable, GetBestAvailableTranslation() should be
118+
used which doesn't consider the messages ID language as being available.
119+
101120
@param domain
102121
The catalog domain to look for.
103122
@@ -142,21 +161,43 @@ class wxTranslations
142161
143162
@return @true if a suitable catalog was found, @false otherwise
144163
145-
@see AddCatalog()
164+
@see AddAvailableCatalog()
146165
*/
147166
bool AddStdCatalog();
148167

149168
/**
150169
Add a catalog for use with the current locale.
151170
152-
By default, it is searched for in standard places (see
171+
By default, the catalog is searched for in standard places (see
153172
wxFileTranslationsLoader), but you may also prepend additional
154173
directories to the search path with
155174
wxFileTranslationsLoader::AddCatalogLookupPathPrefix().
156175
157176
All loaded catalogs will be used for message lookup by GetString() for
158177
the current locale.
159178
179+
@return
180+
@true if catalog was successfully loaded, @false otherwise, usually
181+
because it wasn't found. Note that unlike AddCatalog() this
182+
function returns @false even if the language of the original
183+
strings (usually English) can be used directly, i.e. its return
184+
value only indicates that there are no catalogs available for the
185+
selected or system-default languages, but is not necessarily an
186+
error if no translations are needed in the first place.
187+
188+
@since 3.2.3
189+
*/
190+
bool AddAvailableCatalog(const wxString& domain);
191+
192+
/**
193+
Add a catalog for use with the current locale or fall back to the
194+
original messages language.
195+
196+
This function behaves like AddAvailableCatalog() but also checks if the
197+
strings used in the program, written in @a msgIdLanguage, can be used
198+
without any translations on the current system and also returns @true
199+
in this case, unlike AddAvailableCatalog().
200+
160201
By default, i.e. if @a msgIdLanguage is not given, @c msgid strings are assumed
161202
to be in English and written only using 7-bit ASCII characters.
162203
If you have to deal with non-English strings or 8-bit characters in the
@@ -173,8 +214,10 @@ class wxTranslations
173214
code are used instead.
174215
175216
@return
176-
@true if catalog was successfully loaded, @false otherwise (which might
177-
mean that the catalog is not found or that it isn't in the correct format).
217+
@true if catalog was successfully loaded or loading it is
218+
unnecessary because the original messages can be used directly,
219+
@false otherwise (which might mean that the catalog is not found or
220+
that it isn't in the correct format).
178221
*/
179222
bool AddCatalog(const wxString& domain,
180223
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
@@ -213,7 +256,7 @@ class wxTranslations
213256
According to GNU gettext tradition, each catalog normally corresponds to
214257
'domain' which is more or less the application name.
215258
216-
@see AddCatalog()
259+
@see AddAvailableCatalog()
217260
*/
218261
bool IsLoaded(const wxString& domain) const;
219262

@@ -348,7 +391,7 @@ class wxFileTranslationsLoader : public wxTranslationsLoader
348391
(in this order).
349392
350393
This only applies to subsequent invocations of
351-
wxTranslations::AddCatalog().
394+
wxTranslations::AddAvailableCatalog().
352395
*/
353396
static void AddCatalogLookupPathPrefix(const wxString& prefix);
354397
};
@@ -358,8 +401,7 @@ class wxFileTranslationsLoader : public wxTranslationsLoader
358401
resources.
359402
360403
If you wish to store translation MO files in resources, you have to
361-
enable this loader before calling wxTranslations::AddCatalog() or
362-
wxLocale::AddCatalog():
404+
enable this loader before calling wxTranslations::AddAvailableCatalog():
363405
364406
@code
365407
wxTranslations::Get()->SetLoader(new wxResourceTranslationsLoader);

src/common/translation.cpp

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ bool wxTranslations::AddStdCatalog()
14061406
// the name without the version if it's not found, as message catalogs
14071407
// typically won't have the version in their names under non-Unix platforms
14081408
// (i.e. where they're not installed by our own "make install").
1409-
if ( AddCatalog("wxstd-" wxSTRINGIZE(wxMAJOR_VERSION) "." wxSTRINGIZE(wxMINOR_VERSION)) )
1409+
if ( AddAvailableCatalog("wxstd-" wxSTRINGIZE(wxMAJOR_VERSION) "." wxSTRINGIZE(wxMINOR_VERSION)) )
14101410
return true;
14111411

14121412
if ( AddCatalog(wxS("wxstd")) )
@@ -1425,12 +1425,9 @@ bool wxTranslations::AddCatalog(const wxString& domain,
14251425
}
14261426
#endif // !wxUSE_UNICODE
14271427

1428-
bool wxTranslations::AddCatalog(const wxString& domain,
1429-
wxLanguage msgIdLanguage)
1428+
bool wxTranslations::AddAvailableCatalog(const wxString& domain)
14301429
{
1431-
const wxString msgIdLang = wxUILocale::GetLanguageCanonicalName(msgIdLanguage);
1432-
const wxString domain_lang = GetBestTranslation(domain, msgIdLang);
1433-
1430+
const wxString domain_lang = GetBestAvailableTranslation(domain);
14341431
if ( domain_lang.empty() )
14351432
{
14361433
wxLogTrace(TRACE_I18N,
@@ -1439,18 +1436,40 @@ bool wxTranslations::AddCatalog(const wxString& domain,
14391436
return false;
14401437
}
14411438

1442-
wxLogTrace(TRACE_I18N,
1443-
wxS("adding '%s' translation for domain '%s' (msgid language '%s')"),
1444-
domain_lang, domain, msgIdLang);
1439+
return LoadCatalog(domain, domain_lang, wxString());
1440+
}
1441+
1442+
bool wxTranslations::AddCatalog(const wxString& domain,
1443+
wxLanguage msgIdLanguage)
1444+
{
1445+
if ( AddAvailableCatalog(domain) )
1446+
return true;
1447+
1448+
const wxString msgIdLang = wxUILocale::GetLanguageCanonicalName(msgIdLanguage);
1449+
const wxString domain_lang = GetBestTranslation(domain, msgIdLang);
1450+
1451+
if ( msgIdLang == domain_lang )
1452+
{
1453+
wxLogTrace(TRACE_I18N,
1454+
wxS("not using translations for domain '%s' with msgid language '%s'"),
1455+
domain, msgIdLang);
1456+
return true;
1457+
}
14451458

1446-
return LoadCatalog(domain, domain_lang, msgIdLang);
1459+
return false;
14471460
}
14481461

14491462

14501463
bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang, const wxString& msgIdLang)
14511464
{
14521465
wxCHECK_MSG( m_loader, false, "loader can't be NULL" );
14531466

1467+
// This parameter is kept for ABI compatibility (this function is private,
1468+
// but the automated ABI check still fails if its signature is modified)
1469+
// but not used any longer because the case of domain being equal to
1470+
// msgIdLang is checked in AddCatalog() now.
1471+
wxUnusedVar(msgIdLang);
1472+
14541473
wxMsgCatalog *cat = NULL;
14551474

14561475
#if wxUSE_FONTMAP
@@ -1484,15 +1503,6 @@ bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang, c
14841503
cat = m_loader->LoadCatalog(domain, baselang);
14851504
}
14861505

1487-
if ( !cat )
1488-
{
1489-
// It is OK to not load catalog if the msgid language and m_language match,
1490-
// in which case we can directly display the texts embedded in program's
1491-
// source code:
1492-
if ( msgIdLang == lang )
1493-
return true;
1494-
}
1495-
14961506
if ( cat )
14971507
{
14981508
// add it to the head of the list so that in GetString it will
@@ -1530,14 +1540,56 @@ wxString wxTranslations::GetBestTranslation(const wxString& domain,
15301540
wxString wxTranslations::GetBestTranslation(const wxString& domain,
15311541
const wxString& msgIdLanguage)
15321542
{
1533-
// explicitly set language should always be respected
1543+
wxString lang = GetBestAvailableTranslation(domain);
1544+
if ( lang.empty() )
1545+
{
1546+
wxArrayString available;
1547+
available.push_back(msgIdLanguage);
1548+
available.push_back(msgIdLanguage.BeforeFirst('_'));
1549+
lang = GetPreferredUILanguage(available);
1550+
if ( lang.empty() )
1551+
{
1552+
wxLogTrace(TRACE_I18N,
1553+
"no available language for domain '%s'", domain);
1554+
}
1555+
else
1556+
{
1557+
wxLogTrace(TRACE_I18N,
1558+
"using message ID language '%s' for domain '%s'", lang);
1559+
}
1560+
}
1561+
1562+
return lang;
1563+
}
1564+
1565+
wxString wxTranslations::GetBestAvailableTranslation(const wxString& domain)
1566+
{
1567+
const wxArrayString available(GetAvailableTranslations(domain));
15341568
if ( !m_lang.empty() )
1535-
return m_lang;
1569+
{
1570+
wxLogTrace(TRACE_I18N,
1571+
"searching for best translation to %s for domain '%s'",
1572+
m_lang, domain);
1573+
1574+
wxString lang;
1575+
if ( available.Index(m_lang) != wxNOT_FOUND )
1576+
{
1577+
lang = m_lang;
1578+
}
1579+
else
1580+
{
1581+
const wxString baselang = m_lang.BeforeFirst('_');
1582+
if ( baselang != m_lang && available.Index(baselang) != wxNOT_FOUND )
1583+
lang = baselang;
1584+
}
15361585

1537-
wxArrayString available(GetAvailableTranslations(domain));
1538-
// it's OK to have duplicates, so just add msgid language
1539-
available.push_back(msgIdLanguage);
1540-
available.push_back(msgIdLanguage.BeforeFirst('_'));
1586+
if ( lang.empty() )
1587+
wxLogTrace(TRACE_I18N, " => no available translations found");
1588+
else
1589+
wxLogTrace(TRACE_I18N, " => found '%s'", lang);
1590+
1591+
return lang;
1592+
}
15411593

15421594
wxLogTrace(TRACE_I18N, "choosing best language for domain '%s'", domain);
15431595
LogTraceArray(" - available translations", available);

tests/intl/intltest.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,39 @@ void IntlTestCase::IsAvailable()
237237
CPPUNIT_ASSERT_EQUAL( origLocale, setlocale(LC_ALL, NULL) );
238238
}
239239

240+
TEST_CASE("wxTranslations::Available", "[translations]")
241+
{
242+
// We currently have translations for French and Japanese in this test
243+
// directory, check that loading those succeeds but loading others doesn't.
244+
wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
245+
246+
const wxString domain("internat");
247+
248+
wxTranslations trans;
249+
250+
SECTION("All")
251+
{
252+
wxArrayString available = trans.GetAvailableTranslations(domain);
253+
REQUIRE( available.size() == 2 );
254+
255+
available.Sort();
256+
CHECK( available[0] == "fr" );
257+
CHECK( available[1] == "ja" );
258+
}
259+
260+
SECTION("French")
261+
{
262+
trans.SetLanguage(wxLANGUAGE_FRENCH);
263+
CHECK( trans.AddAvailableCatalog(domain) );
264+
}
265+
266+
SECTION("Italian")
267+
{
268+
trans.SetLanguage(wxLANGUAGE_ITALIAN);
269+
CHECK_FALSE( trans.AddAvailableCatalog(domain) );
270+
}
271+
}
272+
240273
// The test may fail in ANSI builds because of unsupported encoding, but we
241274
// don't really care about this build anyhow, so just skip it there.
242275
#if wxUSE_UNICODE

version-script.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
extern "C++" {
3232
"wxGLCanvasEGL::CreateWaylandSubsurface";
3333
"wxGLCanvasEGL::DestroyWaylandSubsurface";
34+
"wxTranslations::AddAvailableCatalog";
35+
"wxTranslations::GetBestAvailableTranslation";
3436
"wxUILocale::GetMonthName";
3537
"wxUILocale::GetWeekDayName";
3638
};

0 commit comments

Comments
 (0)