mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-18 01:19:45 +08:00
Revert "Change return type of wxGetTranslation"
This reverts commit 02cff90601 because it
broke a lot of existing code which did anything that boiled down to
const char* whatever = _("Some message");
because the pointer became dangling instead of pointing to the memory
used by the cached translated string.
See #26195.
This commit is contained in:
+6
-6
@@ -210,16 +210,16 @@ public:
|
||||
//
|
||||
// domains are searched in the last to first order, i.e. catalogs
|
||||
// added later override those added before.
|
||||
wxString GetString(const wxString& origString,
|
||||
const wxString& domain = wxEmptyString) const
|
||||
const wxString& GetString(const wxString& origString,
|
||||
const wxString& domain = wxEmptyString) const
|
||||
{
|
||||
return wxGetTranslation(origString, domain);
|
||||
}
|
||||
// plural form version of the same:
|
||||
wxString GetString(const wxString& origString,
|
||||
const wxString& origString2,
|
||||
unsigned n,
|
||||
const wxString& domain = wxEmptyString) const
|
||||
const wxString& GetString(const wxString& origString,
|
||||
const wxString& origString2,
|
||||
unsigned n,
|
||||
const wxString& domain = wxEmptyString) const
|
||||
{
|
||||
return wxGetTranslation(origString, origString2, n, domain);
|
||||
}
|
||||
|
||||
+48
-44
@@ -179,11 +179,10 @@ public:
|
||||
wxString GetHeaderValue(const wxString& header,
|
||||
const wxString& domain = wxEmptyString) const;
|
||||
|
||||
|
||||
wxDEPRECATED_INLINE(
|
||||
static const wxString& GetUntranslatedString(const wxString& str),
|
||||
return str;
|
||||
)
|
||||
// this is hack to work around a problem with wxGetTranslation() which
|
||||
// returns const wxString& and not wxString, so when it returns untranslated
|
||||
// string, it needs to have a copy of it somewhere
|
||||
static const wxString& GetUntranslatedString(const wxString& str);
|
||||
|
||||
private:
|
||||
enum class Translations
|
||||
@@ -275,9 +274,9 @@ protected:
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// get the translation of the string in the current locale
|
||||
inline wxString wxGetTranslation(const wxString& str,
|
||||
const wxString& domain = wxString(),
|
||||
const wxString& context = wxString())
|
||||
inline const wxString& wxGetTranslation(const wxString& str,
|
||||
const wxString& domain = wxString(),
|
||||
const wxString& context = wxString())
|
||||
{
|
||||
wxTranslations *trans = wxTranslations::Get();
|
||||
const wxString *transStr = trans ? trans->GetTranslatedString(str, domain, context)
|
||||
@@ -285,14 +284,16 @@ inline wxString wxGetTranslation(const wxString& str,
|
||||
if ( transStr )
|
||||
return *transStr;
|
||||
else
|
||||
return str;
|
||||
// NB: this function returns reference to a string, so we have to keep
|
||||
// a copy of it somewhere
|
||||
return wxTranslations::GetUntranslatedString(str);
|
||||
}
|
||||
|
||||
inline wxString wxGetTranslation(const wxString& str1,
|
||||
const wxString& str2,
|
||||
unsigned n,
|
||||
const wxString& domain = wxString(),
|
||||
const wxString& context = wxString())
|
||||
inline const wxString& wxGetTranslation(const wxString& str1,
|
||||
const wxString& str2,
|
||||
unsigned n,
|
||||
const wxString& domain = wxString(),
|
||||
const wxString& context = wxString())
|
||||
{
|
||||
wxTranslations *trans = wxTranslations::Get();
|
||||
const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain, context)
|
||||
@@ -300,7 +301,11 @@ inline wxString wxGetTranslation(const wxString& str1,
|
||||
if ( transStr )
|
||||
return *transStr;
|
||||
else
|
||||
return n == 1 ? str1 : str2;
|
||||
// NB: this function returns reference to a string, so we have to keep
|
||||
// a copy of it somewhere
|
||||
return n == 1
|
||||
? wxTranslations::GetUntranslatedString(str1)
|
||||
: wxTranslations::GetUntranslatedString(str2);
|
||||
}
|
||||
|
||||
#ifdef wxNO_IMPLICIT_WXSTRING_ENCODING
|
||||
@@ -309,20 +314,19 @@ inline wxString wxGetTranslation(const wxString& str1,
|
||||
* It must always be possible to call wxGetTranslation() with const
|
||||
* char* arguments.
|
||||
*/
|
||||
|
||||
inline wxString wxGetTranslation(const char *str,
|
||||
const char *domain = "",
|
||||
const char *context = "") {
|
||||
inline const wxString& wxGetTranslation(const char *str,
|
||||
const char *domain = "",
|
||||
const char *context = "") {
|
||||
const wxMBConv &conv = wxConvWhateverWorks;
|
||||
return wxGetTranslation(wxString(str, conv), wxString(domain, conv),
|
||||
wxString(context, conv));
|
||||
}
|
||||
|
||||
inline wxString wxGetTranslation(const char *str1,
|
||||
const char *str2,
|
||||
unsigned n,
|
||||
const char *domain = "",
|
||||
const char *context = "") {
|
||||
inline const wxString& wxGetTranslation(const char *str1,
|
||||
const char *str2,
|
||||
unsigned n,
|
||||
const char *domain = "",
|
||||
const char *context = "") {
|
||||
const wxMBConv &conv = wxConvWhateverWorks;
|
||||
return wxGetTranslation(wxString(str1, conv), wxString(str2, conv), n,
|
||||
wxString(domain, conv),
|
||||
@@ -379,7 +383,7 @@ inline wxString wxTRANS_INPUT_STR(const wchar_t* s)
|
||||
*/
|
||||
|
||||
template<size_t N, typename T>
|
||||
wxString wxUnderscoreWrapper(const T (&msg)[N])
|
||||
const wxString& wxUnderscoreWrapper(const T (&msg)[N])
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg));
|
||||
}
|
||||
@@ -392,9 +396,9 @@ wxString wxUnderscoreWrapper(T)
|
||||
}
|
||||
|
||||
template<size_t M, size_t N, typename T>
|
||||
wxString wxPluralWrapper(const T (&msg)[M],
|
||||
const T (&plural)[N],
|
||||
int count)
|
||||
const wxString& wxPluralWrapper(const T (&msg)[M],
|
||||
const T (&plural)[N],
|
||||
int count)
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||
count);
|
||||
@@ -408,8 +412,8 @@ wxString wxPluralWrapper(T, U, int)
|
||||
}
|
||||
|
||||
template<size_t M, size_t N, typename T>
|
||||
wxString wxGettextInContextWrapper(const T (&ctx)[M],
|
||||
const T (&msg)[N])
|
||||
const wxString& wxGettextInContextWrapper(const T (&ctx)[M],
|
||||
const T (&msg)[N])
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxString(),
|
||||
wxTRANS_INPUT_STR(ctx));
|
||||
@@ -423,10 +427,10 @@ wxString wxGettextInContextWrapper(T, U)
|
||||
}
|
||||
|
||||
template<size_t L, size_t M, size_t N, typename T>
|
||||
wxString wxGettextInContextPluralWrapper(const T (&ctx)[L],
|
||||
const T (&msg)[M],
|
||||
const T (&plural)[N],
|
||||
int count)
|
||||
const wxString& wxGettextInContextPluralWrapper(const T (&ctx)[L],
|
||||
const T (&msg)[M],
|
||||
const T (&plural)[N],
|
||||
int count)
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||
count, wxString(), wxTRANS_INPUT_STR(ctx));
|
||||
@@ -443,30 +447,30 @@ wxString wxGettextInContextPluralWrapper(T, U, V, int)
|
||||
|
||||
// Wrapper functions that accept both string literals and variables
|
||||
// as arguments.
|
||||
inline wxString wxUnderscoreWrapper(const char *msg)
|
||||
inline const wxString& wxUnderscoreWrapper(const char *msg)
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg));
|
||||
}
|
||||
|
||||
inline wxString wxPluralWrapper(const char *msg,
|
||||
const char *plural,
|
||||
int count)
|
||||
inline const wxString& wxPluralWrapper(const char *msg,
|
||||
const char *plural,
|
||||
int count)
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||
count);
|
||||
}
|
||||
|
||||
inline wxString wxGettextInContextWrapper(const char *ctx,
|
||||
const char *msg)
|
||||
inline const wxString& wxGettextInContextWrapper(const char *ctx,
|
||||
const char *msg)
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxString(),
|
||||
wxTRANS_INPUT_STR(ctx));
|
||||
}
|
||||
|
||||
inline wxString wxGettextInContextPluralWrapper(const char *ctx,
|
||||
const char *msg,
|
||||
const char *plural,
|
||||
int count)
|
||||
inline const wxString& wxGettextInContextPluralWrapper(const char *ctx,
|
||||
const char *msg,
|
||||
const char *plural,
|
||||
int count)
|
||||
{
|
||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||
count, wxString(), wxTRANS_INPUT_STR(ctx));
|
||||
|
||||
+5
-5
@@ -494,15 +494,15 @@ public:
|
||||
/**
|
||||
Calls wxGetTranslation(const wxString&, const wxString&).
|
||||
*/
|
||||
wxString GetString(const wxString& origString,
|
||||
const wxString& domain = wxEmptyString) const;
|
||||
const wxString& GetString(const wxString& origString,
|
||||
const wxString& domain = wxEmptyString) const;
|
||||
|
||||
/**
|
||||
Calls wxGetTranslation(const wxString&, const wxString&, unsigned, const wxString&).
|
||||
*/
|
||||
wxString GetString(const wxString& origString,
|
||||
const wxString& origString2, unsigned n,
|
||||
const wxString& domain = wxEmptyString) const;
|
||||
const wxString& GetString(const wxString& origString,
|
||||
const wxString& origString2, unsigned n,
|
||||
const wxString& domain = wxEmptyString) const;
|
||||
|
||||
/**
|
||||
Returns current platform-specific locale name as passed to setlocale().
|
||||
|
||||
@@ -612,9 +612,9 @@ public:
|
||||
|
||||
@header{wx/intl.h}
|
||||
*/
|
||||
wxString wxGetTranslation(const wxString& string,
|
||||
const wxString& domain = wxEmptyString,
|
||||
const wxString& context = wxEmptyString);
|
||||
const wxString& wxGetTranslation(const wxString& string,
|
||||
const wxString& domain = wxEmptyString,
|
||||
const wxString& context = wxEmptyString);
|
||||
|
||||
/**
|
||||
This is an overloaded version of
|
||||
@@ -638,10 +638,10 @@ wxString wxGetTranslation(const wxString& string,
|
||||
|
||||
@header{wx/intl.h}
|
||||
*/
|
||||
wxString wxGetTranslation(const wxString& string,
|
||||
const wxString& plural, unsigned n,
|
||||
const wxString& domain = wxEmptyString,
|
||||
const wxString& context = wxEmptyString);
|
||||
const wxString& wxGetTranslation(const wxString& string,
|
||||
const wxString& plural, unsigned n,
|
||||
const wxString& domain = wxEmptyString,
|
||||
const wxString& context = wxEmptyString);
|
||||
|
||||
/**
|
||||
Macro to be used around all literal strings that should be translated.
|
||||
|
||||
@@ -53,7 +53,12 @@
|
||||
#include "wx/msw/missing.h"
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// simple types
|
||||
@@ -1450,6 +1455,97 @@ wxString wxTranslations::DoGetBestAvailableTranslation(const wxString& domain, c
|
||||
return lang;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// We use this container to store all strings known not to have translations.
|
||||
// It is thread-specific to avoid using mutexes for every untranslated string
|
||||
// access.
|
||||
using UntranslatedStrings = std::unordered_set<wxString>;
|
||||
|
||||
/*
|
||||
As of October 2025, MinGW still has a long-standing bug in its thread_local
|
||||
variables implementation: their memory is de-allocated *before* their
|
||||
destructor is called, see https://github.com/msys2/MINGW-packages/issues/2519
|
||||
|
||||
The UntranslatedStringHolder class works around this issue, by storing data
|
||||
in global variables outside of this class and only relying on the dtor to
|
||||
be executed when any thread (not necessarily created by wxWidgets) exits to
|
||||
ensure that we always perform the required cleanup.
|
||||
*/
|
||||
#ifdef __MINGW32__
|
||||
|
||||
class UntranslatedStringHolder
|
||||
{
|
||||
private:
|
||||
static wxCriticalSection ms_criticalSection;
|
||||
static std::map<wxThreadIdType, UntranslatedStrings> ms_setsMap;
|
||||
|
||||
// This will be set to point to an element of ms_setsMap.
|
||||
UntranslatedStrings* m_holder = nullptr;
|
||||
|
||||
public:
|
||||
UntranslatedStringHolder() = default;
|
||||
|
||||
const wxString& get(const wxString& str)
|
||||
{
|
||||
if ( m_holder == nullptr )
|
||||
{
|
||||
wxCriticalSectionLocker locker(ms_criticalSection);
|
||||
m_holder = &ms_setsMap[wxThread::GetCurrentId()];
|
||||
}
|
||||
|
||||
return *m_holder->insert(str).first;
|
||||
}
|
||||
|
||||
~UntranslatedStringHolder()
|
||||
{
|
||||
// This code is run after this object memory has been deallocated so we
|
||||
// cannot access any member variables, but we can access global ones.
|
||||
wxCriticalSectionLocker locker(ms_criticalSection);
|
||||
ms_setsMap.erase(wxThread::GetCurrentId());
|
||||
}
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(UntranslatedStringHolder);
|
||||
};
|
||||
|
||||
wxCriticalSection UntranslatedStringHolder::ms_criticalSection;
|
||||
|
||||
std::map<wxThreadIdType, UntranslatedStrings> UntranslatedStringHolder::ms_setsMap;
|
||||
|
||||
#else // !__MINGW32__
|
||||
|
||||
// When not using MinGW, thread_local variables to work correctly but we still
|
||||
// define this class, even if it's trivial, to use the same code below.
|
||||
class UntranslatedStringHolder
|
||||
{
|
||||
private:
|
||||
UntranslatedStrings m_holder;
|
||||
|
||||
public:
|
||||
UntranslatedStringHolder() = default;
|
||||
|
||||
const wxString& get(const wxString& str)
|
||||
{
|
||||
return *m_holder.insert(str).first;
|
||||
}
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(UntranslatedStringHolder);
|
||||
};
|
||||
|
||||
#endif // __MINGW32__/!__MINGW32__
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
|
||||
/* static */
|
||||
const wxString& wxTranslations::GetUntranslatedString(const wxString& str)
|
||||
{
|
||||
thread_local UntranslatedStringHolder wxPerThreadStrings;
|
||||
return wxPerThreadStrings.get(str);
|
||||
}
|
||||
|
||||
|
||||
const wxString *wxTranslations::GetTranslatedString(const wxString& origString,
|
||||
const wxString& domain,
|
||||
const wxString& context) const
|
||||
|
||||
Reference in New Issue
Block a user