mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-09-27 19:17:06 +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
|
// domains are searched in the last to first order, i.e. catalogs
|
||||||
// added later override those added before.
|
// added later override those added before.
|
||||||
wxString GetString(const wxString& origString,
|
const wxString& GetString(const wxString& origString,
|
||||||
const wxString& domain = wxEmptyString) const
|
const wxString& domain = wxEmptyString) const
|
||||||
{
|
{
|
||||||
return wxGetTranslation(origString, domain);
|
return wxGetTranslation(origString, domain);
|
||||||
}
|
}
|
||||||
// plural form version of the same:
|
// plural form version of the same:
|
||||||
wxString GetString(const wxString& origString,
|
const wxString& GetString(const wxString& origString,
|
||||||
const wxString& origString2,
|
const wxString& origString2,
|
||||||
unsigned n,
|
unsigned n,
|
||||||
const wxString& domain = wxEmptyString) const
|
const wxString& domain = wxEmptyString) const
|
||||||
{
|
{
|
||||||
return wxGetTranslation(origString, origString2, n, domain);
|
return wxGetTranslation(origString, origString2, n, domain);
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-44
@@ -179,11 +179,10 @@ public:
|
|||||||
wxString GetHeaderValue(const wxString& header,
|
wxString GetHeaderValue(const wxString& header,
|
||||||
const wxString& domain = wxEmptyString) const;
|
const wxString& domain = wxEmptyString) const;
|
||||||
|
|
||||||
|
// this is hack to work around a problem with wxGetTranslation() which
|
||||||
wxDEPRECATED_INLINE(
|
// returns const wxString& and not wxString, so when it returns untranslated
|
||||||
static const wxString& GetUntranslatedString(const wxString& str),
|
// string, it needs to have a copy of it somewhere
|
||||||
return str;
|
static const wxString& GetUntranslatedString(const wxString& str);
|
||||||
)
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Translations
|
enum class Translations
|
||||||
@@ -275,9 +274,9 @@ protected:
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// get the translation of the string in the current locale
|
// get the translation of the string in the current locale
|
||||||
inline wxString wxGetTranslation(const wxString& str,
|
inline const wxString& wxGetTranslation(const wxString& str,
|
||||||
const wxString& domain = wxString(),
|
const wxString& domain = wxString(),
|
||||||
const wxString& context = wxString())
|
const wxString& context = wxString())
|
||||||
{
|
{
|
||||||
wxTranslations *trans = wxTranslations::Get();
|
wxTranslations *trans = wxTranslations::Get();
|
||||||
const wxString *transStr = trans ? trans->GetTranslatedString(str, domain, context)
|
const wxString *transStr = trans ? trans->GetTranslatedString(str, domain, context)
|
||||||
@@ -285,14 +284,16 @@ inline wxString wxGetTranslation(const wxString& str,
|
|||||||
if ( transStr )
|
if ( transStr )
|
||||||
return *transStr;
|
return *transStr;
|
||||||
else
|
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,
|
inline const wxString& wxGetTranslation(const wxString& str1,
|
||||||
const wxString& str2,
|
const wxString& str2,
|
||||||
unsigned n,
|
unsigned n,
|
||||||
const wxString& domain = wxString(),
|
const wxString& domain = wxString(),
|
||||||
const wxString& context = wxString())
|
const wxString& context = wxString())
|
||||||
{
|
{
|
||||||
wxTranslations *trans = wxTranslations::Get();
|
wxTranslations *trans = wxTranslations::Get();
|
||||||
const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain, context)
|
const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain, context)
|
||||||
@@ -300,7 +301,11 @@ inline wxString wxGetTranslation(const wxString& str1,
|
|||||||
if ( transStr )
|
if ( transStr )
|
||||||
return *transStr;
|
return *transStr;
|
||||||
else
|
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
|
#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
|
* It must always be possible to call wxGetTranslation() with const
|
||||||
* char* arguments.
|
* char* arguments.
|
||||||
*/
|
*/
|
||||||
|
inline const wxString& wxGetTranslation(const char *str,
|
||||||
inline wxString wxGetTranslation(const char *str,
|
const char *domain = "",
|
||||||
const char *domain = "",
|
const char *context = "") {
|
||||||
const char *context = "") {
|
|
||||||
const wxMBConv &conv = wxConvWhateverWorks;
|
const wxMBConv &conv = wxConvWhateverWorks;
|
||||||
return wxGetTranslation(wxString(str, conv), wxString(domain, conv),
|
return wxGetTranslation(wxString(str, conv), wxString(domain, conv),
|
||||||
wxString(context, conv));
|
wxString(context, conv));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline wxString wxGetTranslation(const char *str1,
|
inline const wxString& wxGetTranslation(const char *str1,
|
||||||
const char *str2,
|
const char *str2,
|
||||||
unsigned n,
|
unsigned n,
|
||||||
const char *domain = "",
|
const char *domain = "",
|
||||||
const char *context = "") {
|
const char *context = "") {
|
||||||
const wxMBConv &conv = wxConvWhateverWorks;
|
const wxMBConv &conv = wxConvWhateverWorks;
|
||||||
return wxGetTranslation(wxString(str1, conv), wxString(str2, conv), n,
|
return wxGetTranslation(wxString(str1, conv), wxString(str2, conv), n,
|
||||||
wxString(domain, conv),
|
wxString(domain, conv),
|
||||||
@@ -379,7 +383,7 @@ inline wxString wxTRANS_INPUT_STR(const wchar_t* s)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template<size_t N, typename T>
|
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));
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg));
|
||||||
}
|
}
|
||||||
@@ -392,9 +396,9 @@ wxString wxUnderscoreWrapper(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t M, size_t N, typename T>
|
template<size_t M, size_t N, typename T>
|
||||||
wxString wxPluralWrapper(const T (&msg)[M],
|
const wxString& wxPluralWrapper(const T (&msg)[M],
|
||||||
const T (&plural)[N],
|
const T (&plural)[N],
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||||
count);
|
count);
|
||||||
@@ -408,8 +412,8 @@ wxString wxPluralWrapper(T, U, int)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t M, size_t N, typename T>
|
template<size_t M, size_t N, typename T>
|
||||||
wxString wxGettextInContextWrapper(const T (&ctx)[M],
|
const wxString& wxGettextInContextWrapper(const T (&ctx)[M],
|
||||||
const T (&msg)[N])
|
const T (&msg)[N])
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxString(),
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxString(),
|
||||||
wxTRANS_INPUT_STR(ctx));
|
wxTRANS_INPUT_STR(ctx));
|
||||||
@@ -423,10 +427,10 @@ wxString wxGettextInContextWrapper(T, U)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t L, size_t M, size_t N, typename T>
|
template<size_t L, size_t M, size_t N, typename T>
|
||||||
wxString wxGettextInContextPluralWrapper(const T (&ctx)[L],
|
const wxString& wxGettextInContextPluralWrapper(const T (&ctx)[L],
|
||||||
const T (&msg)[M],
|
const T (&msg)[M],
|
||||||
const T (&plural)[N],
|
const T (&plural)[N],
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||||
count, wxString(), wxTRANS_INPUT_STR(ctx));
|
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
|
// Wrapper functions that accept both string literals and variables
|
||||||
// as arguments.
|
// as arguments.
|
||||||
inline wxString wxUnderscoreWrapper(const char *msg)
|
inline const wxString& wxUnderscoreWrapper(const char *msg)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg));
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline wxString wxPluralWrapper(const char *msg,
|
inline const wxString& wxPluralWrapper(const char *msg,
|
||||||
const char *plural,
|
const char *plural,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||||
count);
|
count);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline wxString wxGettextInContextWrapper(const char *ctx,
|
inline const wxString& wxGettextInContextWrapper(const char *ctx,
|
||||||
const char *msg)
|
const char *msg)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxString(),
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxString(),
|
||||||
wxTRANS_INPUT_STR(ctx));
|
wxTRANS_INPUT_STR(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline wxString wxGettextInContextPluralWrapper(const char *ctx,
|
inline const wxString& wxGettextInContextPluralWrapper(const char *ctx,
|
||||||
const char *msg,
|
const char *msg,
|
||||||
const char *plural,
|
const char *plural,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
return wxGetTranslation(wxTRANS_INPUT_STR(msg), wxTRANS_INPUT_STR(plural),
|
||||||
count, wxString(), wxTRANS_INPUT_STR(ctx));
|
count, wxString(), wxTRANS_INPUT_STR(ctx));
|
||||||
|
|||||||
+5
-5
@@ -494,15 +494,15 @@ public:
|
|||||||
/**
|
/**
|
||||||
Calls wxGetTranslation(const wxString&, const wxString&).
|
Calls wxGetTranslation(const wxString&, const wxString&).
|
||||||
*/
|
*/
|
||||||
wxString GetString(const wxString& origString,
|
const wxString& GetString(const wxString& origString,
|
||||||
const wxString& domain = wxEmptyString) const;
|
const wxString& domain = wxEmptyString) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Calls wxGetTranslation(const wxString&, const wxString&, unsigned, const wxString&).
|
Calls wxGetTranslation(const wxString&, const wxString&, unsigned, const wxString&).
|
||||||
*/
|
*/
|
||||||
wxString GetString(const wxString& origString,
|
const wxString& GetString(const wxString& origString,
|
||||||
const wxString& origString2, unsigned n,
|
const wxString& origString2, unsigned n,
|
||||||
const wxString& domain = wxEmptyString) const;
|
const wxString& domain = wxEmptyString) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns current platform-specific locale name as passed to setlocale().
|
Returns current platform-specific locale name as passed to setlocale().
|
||||||
|
|||||||
@@ -612,9 +612,9 @@ public:
|
|||||||
|
|
||||||
@header{wx/intl.h}
|
@header{wx/intl.h}
|
||||||
*/
|
*/
|
||||||
wxString wxGetTranslation(const wxString& string,
|
const wxString& wxGetTranslation(const wxString& string,
|
||||||
const wxString& domain = wxEmptyString,
|
const wxString& domain = wxEmptyString,
|
||||||
const wxString& context = wxEmptyString);
|
const wxString& context = wxEmptyString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This is an overloaded version of
|
This is an overloaded version of
|
||||||
@@ -638,10 +638,10 @@ wxString wxGetTranslation(const wxString& string,
|
|||||||
|
|
||||||
@header{wx/intl.h}
|
@header{wx/intl.h}
|
||||||
*/
|
*/
|
||||||
wxString wxGetTranslation(const wxString& string,
|
const wxString& wxGetTranslation(const wxString& string,
|
||||||
const wxString& plural, unsigned n,
|
const wxString& plural, unsigned n,
|
||||||
const wxString& domain = wxEmptyString,
|
const wxString& domain = wxEmptyString,
|
||||||
const wxString& context = wxEmptyString);
|
const wxString& context = wxEmptyString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Macro to be used around all literal strings that should be translated.
|
Macro to be used around all literal strings that should be translated.
|
||||||
|
|||||||
@@ -53,7 +53,12 @@
|
|||||||
#include "wx/msw/missing.h"
|
#include "wx/msw/missing.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#include <map>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// simple types
|
// simple types
|
||||||
@@ -1450,6 +1455,97 @@ wxString wxTranslations::DoGetBestAvailableTranslation(const wxString& domain, c
|
|||||||
return lang;
|
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 *wxTranslations::GetTranslatedString(const wxString& origString,
|
||||||
const wxString& domain,
|
const wxString& domain,
|
||||||
const wxString& context) const
|
const wxString& context) const
|
||||||
|
|||||||
Reference in New Issue
Block a user