diff --git a/include/audacity/Types.h b/include/audacity/Types.h index fd121fba7..1819ad150 100644 --- a/include/audacity/Types.h +++ b/include/audacity/Types.h @@ -348,9 +348,11 @@ public: // Returns true if context is NullContextFormatter bool IsVerbatim() const; - // Capture variadic format arguments (by copy). The subsitution is + // Capture variadic format arguments (by copy). The substitution is // computed later in a call to Translate() after msgid is looked up in the // translation catalog. + // Any format arguments that are also of type TranslatableString will be + // translated too at substitution time template TranslatableString&& Format( Args&&... args ) && { @@ -361,17 +363,34 @@ public: if (str.empty()) return context; else - return wxString::Format( str, args... ); + return wxString::Format( + str, TranslatableString::TranslateArgument(args)... ); }; return std::move( *this ); } + // Append another translatable string; lookup of msgids for + // this and for the argument are both delayed until Translate() is invoked + // on this, and then the formatter concatenates the translations + TranslatableString &operator +=( const TranslatableString &arg ); + friend std::hash< TranslatableString >; private: + template< typename T > static const T &TranslateArgument( const T &arg ) + { return arg; } + static wxString TranslateArgument ( const TranslatableString &arg ) + { return arg.Translation(); } + Formatter mFormatter; }; +inline TranslatableString operator +( + const TranslatableString &x, const TranslatableString &y ) +{ + return TranslatableString{ x } += y; +} + using TranslatableStrings = std::vector; // For using std::unordered_map on TranslatableString diff --git a/src/Internat.cpp b/src/Internat.cpp index b0c006714..328d55bb6 100644 --- a/src/Internat.cpp +++ b/src/Internat.cpp @@ -240,7 +240,7 @@ bool Internat::SanitiseFilename(wxString &name, const wxString &sub) // Special Mac stuff // '/' is permitted in file names as seen in dialogs, even though it is // the path separator. The "real" filename as seen in the terminal has ':'. - // Do NOT return true if this is the only subsitution. + // Do NOT return true if this is the only substitution. name.Replace(wxT("/"), wxT(":")); #endif @@ -325,3 +325,17 @@ wxString TranslatableString::Translation() const return result; } + +TranslatableString &TranslatableString::operator +=( + const TranslatableString &arg ) +{ + auto prevFormatter = mFormatter; + mFormatter = [prevFormatter, arg](const wxString &str){ + if (str.empty()) + return prevFormatter ? prevFormatter({}) : wxString{}; + else + return (prevFormatter ? prevFormatter(str) : str) + + arg.Translation(); + }; + return *this; +}