1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-20 09:31:15 +02:00

TranslatableString can store a context and format arguments...

... Format arguments are substituted into the translation of the msgid, which
may not be known at the time the format arguments are captured (because locale
may change).  This allows TranslatableString with arguments to be constructed
at static initialization time.

There is also a special "verbatim" or null context which makes no translations
of msgids.

There is not yet any use of other contexts besides default or null.
This commit is contained in:
Paul Licameli
2019-12-03 11:34:50 -05:00
parent 4fdd1b005c
commit 15260c2c95
9 changed files with 103 additions and 35 deletions

View File

@@ -68,12 +68,12 @@ public:
// Allows implicit construction from an internal string re-used as a msgid
ComponentInterfaceSymbol( const wxString &internal )
: mInternal{ internal }, mMsgid{ internal }
: mInternal{ internal }, mMsgid{ internal, {} }
{}
// Allows implicit construction from an internal string re-used as a msgid
ComponentInterfaceSymbol( const wxChar *msgid )
: mInternal{ msgid }, mMsgid{ msgid }
: mInternal{ msgid }, mMsgid{ msgid, {} }
{}
// Two-argument version distinguishes internal from translatable string
@@ -87,7 +87,7 @@ public:
const wxString &Internal() const { return mInternal; }
const TranslatableString &Msgid() const { return mMsgid; }
const wxString &Translation() const { return mMsgid.Translation(); }
const wxString Translation() const { return mMsgid.Translation(); }
bool empty() const { return mInternal.empty(); }
@@ -135,7 +135,7 @@ public:
virtual wxString GetDescription() = 0;
// non-virtual convenience function
const wxString& GetTranslatedName();
const wxString GetTranslatedName();
// Parameters, if defined. false means no defined parameters.
virtual bool DefineParams( ShuttleParams & WXUNUSED(S) ){ return false;};

View File

@@ -43,6 +43,7 @@
#define __AUDACITY_TYPES_H__
#include <algorithm>
#include <functional>
#include <type_traits>
#include <vector>
#include <wx/debug.h> // for wxASSERT
@@ -292,8 +293,8 @@ using CommandID = TaggedIdentifier< CommandIdTag, false >;
using CommandIDs = std::vector<CommandID>;
// Holds a msgid for the translation catalog (and in future, might also hold a
// second, disambiguating context string)
// Holds a msgid for the translation catalog and may also hold a context string
// and a formatter closure that captures formatting arguments
//
// Two different wxString accessors -- one for the msgid itself, another for
// the user-visible translation. The msgid should be used only in unusual cases
@@ -302,10 +303,28 @@ using CommandIDs = std::vector<CommandID>;
// Implicit conversions to and from wxString are intentionally disabled
class TranslatableString : private wxString {
public:
// A dual-purpose function
// Given the empty string, return a context string
// Given the translation of the msgid into the current locale, substitute
// format arguments into it
using Formatter = std::function< wxString(const wxString &) >;
// This special formatter causes msgids to be used verbatim, not looked up
// in any catalog
static const Formatter NullContextFormatter;
TranslatableString() {}
explicit TranslatableString(const wxString &str) : wxString{ str } {}
explicit TranslatableString(const wxChar *str) : wxString{ str } {}
// Supply {} for the second argument to cause lookup of the msgid with
// empty context string
explicit TranslatableString(
const wxString &str, Formatter formatter = NullContextFormatter)
: wxString{ str }, mFormatter{ std::move(formatter) } {}
// Supply {} for the second argument to cause lookup of the msgid with
// empty context string
explicit TranslatableString(
const wxChar *str, Formatter formatter = NullContextFormatter)
: wxString{ str }, mFormatter{ std::move(formatter) } {}
using wxString::empty;
@@ -316,7 +335,7 @@ public:
// This is a deliberately ugly-looking function name. Use with caution.
Identifier MSGID() const { return Identifier{ *this }; }
const wxString &Translation() const;
wxString Translation() const;
friend bool operator == (
const TranslatableString &x, const TranslatableString &y)
@@ -326,8 +345,31 @@ public:
const TranslatableString &x, const TranslatableString &y)
{ return !(x == y); }
// Future: may also store a domain and context, as if for dpgettext()
// Returns true if context is NullContextFormatter
bool IsVerbatim() const;
// Capture variadic format arguments (by copy). The subsitution is
// computed later in a call to Translate() after msgid is looked up in the
// translation catalog.
template <typename... Args>
TranslatableString&& Format( Args&&... args ) &&
{
wxString context;
if ( this->mFormatter )
context = this->mFormatter({});
this->mFormatter = [context, args...](const wxString &str){
if (str.empty())
return context;
else
return wxString::Format( str, args... );
};
return std::move( *this );
}
friend std::hash< TranslatableString >;
private:
Formatter mFormatter;
};
using TranslatableStrings = std::vector<TranslatableString>;