Audacity 3.2.0
TranslatableString.h
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file TranslatableString.h
6
7 Paul Licameli split from Types.h
8
9 **********************************************************************/
10
11#ifndef __AUDACITY_TRANSLATABLE_STRING__
12#define __AUDACITY_TRANSLATABLE_STRING__
13
14#include <stddef.h> // for size_t
15#include <functional>
16#include <wx/string.h>
17
18class Identifier;
19
20#include <vector>
21
23
32class STRINGS_API TranslatableString {
33 enum class Request;
34 template< size_t N > struct PluralTemp;
35
36public:
39
41
45 using Formatter = std::function< wxString(const wxString &, Request) >;
46
48
51 explicit TranslatableString( wxString str, Formatter formatter )
52 : mFormatter{ std::move(formatter) }
53 {
54 mMsgid.swap( str );
55 }
56
57 // copy and move
61 : mFormatter( std::move( str.mFormatter ) )
62 {
63 mMsgid.swap( str.mMsgid );
64 }
66 {
67 mFormatter = std::move( str.mFormatter );
68 mMsgid.swap( str.mMsgid );
69 return *this;
70 }
71
72 bool empty() const { return mMsgid.empty(); }
73
75
77 Identifier MSGID() const;
78
79 wxString Translation() const { return DoFormat( false ); }
80
82 wxString Debug() const { return DoFormat( true ); }
83
85
86 friend bool operator == (
87 const TranslatableString &x, const TranslatableString &y)
88 { return x.mMsgid == y.mMsgid; }
89
90 friend bool operator != (
91 const TranslatableString &x, const TranslatableString &y)
92 { return !(x == y); }
93
95 bool IsVerbatim() const;
96
98
102 template< typename... Args >
103 TranslatableString &Format( Args &&...args ) &
104 {
105 auto prevFormatter = mFormatter;
106 this->mFormatter = [prevFormatter, args...]
107 (const wxString &str, Request request) -> wxString {
108 switch ( request ) {
109 case Request::Context:
110 return TranslatableString::DoGetContext( prevFormatter );
111 case Request::Format:
112 case Request::DebugFormat:
113 default: {
114 bool debug = request == Request::DebugFormat;
115 return wxString::Format(
117 prevFormatter,
118 str, TranslatableString::DoGetContext( prevFormatter ),
119 debug ),
121 );
122 }
123 }
124 };
125 return *this;
126 }
127 template< typename... Args >
128 TranslatableString &&Format( Args &&...args ) &&
129 {
130 return std::move( Format( std::forward<Args>(args)... ) );
131 }
132
134
137 TranslatableString &Context( const wxString &context ) &
138 {
139 this->mFormatter = [context]
140 (const wxString &str, Request request) -> wxString {
141 switch ( request ) {
142 case Request::Context:
143 return context;
144 case Request::DebugFormat:
145 return DoSubstitute( {}, str, context, true );
146 case Request::Format:
147 default:
148 return DoSubstitute( {}, str, context, false );
149 }
150 };
151 return *this;
152 }
153 TranslatableString &&Context( const wxString &context ) &&
154 {
155 return std::move( Context( context ) );
156 }
157
159
163 TranslatableString arg, const wxString &separator = {} ) &;
165 TranslatableString arg, const wxString &separator = {} ) &&
166 { return std::move( Join( std::move(arg), separator ) ); }
167
169 {
170 Join( std::move( arg ) );
171 return *this;
172 }
173
175
179 template< size_t N >
180 PluralTemp< N > Plural( const wxString &pluralStr ) &&
181 {
182 return PluralTemp< N >{ *this, pluralStr };
183 }
184
188 enum StripOptions : unsigned {
189 // Values to be combined with bitwise OR
190 MenuCodes = 0x1,
191 Ellipses = 0x2,
192 };
193 TranslatableString &Strip( unsigned options = MenuCodes ) &;
194 TranslatableString &&Strip( unsigned options = MenuCodes ) &&
195 { return std::move( Strip( options ) ); }
196
198 TranslatableString Stripped( unsigned options = MenuCodes ) const
199 { return TranslatableString{ *this }.Strip( options ); }
200
201 wxString StrippedTranslation() const { return Stripped().Translation(); }
202
203private:
205
207 explicit TranslatableString( wxString str )
208 : mFormatter{ NullContextFormatter }
209 {
210 mMsgid.swap( str );
211 }
212
213 friend TranslatableString Verbatim( wxString str );
214
215 enum class Request {
216 Context,
217 Format,
218 DebugFormat,
219 };
220
221 static const wxChar *const NullContextName;
223
224 static wxString DoGetContext( const Formatter &formatter );
225 static wxString DoSubstitute(
226 const Formatter &formatter,
227 const wxString &format, const wxString &context, bool debug );
228 wxString DoFormat( bool debug ) const
229 { return DoSubstitute(
230 mFormatter, mMsgid, DoGetContext(mFormatter), debug ); }
231
232 static wxString DoChooseFormat(
233 const Formatter &formatter,
234 const wxString &singular, const wxString &plural, unsigned nn, bool debug );
235
236 template< typename T > static const T &TranslateArgument( const T &arg, bool )
237 { return arg; }
239
240 template< typename T > static auto TranslateArgument(
241 const std::reference_wrapper<T> &arg, bool debug )
242 -> decltype(
243 TranslatableString::TranslateArgument( arg.get(), debug ) )
244 { return TranslatableString::TranslateArgument( arg.get(), debug ); }
245 static wxString TranslateArgument( const TranslatableString &arg, bool debug )
246 { return arg.DoFormat( debug ); }
247
248 template< size_t N > struct PluralTemp{
250 const wxString &pluralStr;
251 template< typename... Args >
252 TranslatableString &&operator()( Args&&... args )
253 {
254 // Pick from the pack the argument that specifies number
255 auto selector =
256 std::template get< N >( std::forward_as_tuple( args... ) );
257 // We need an unsigned value. Guard against negative values.
258 auto nn = static_cast<unsigned>(
259 std::max<unsigned long long>( 0, selector )
260 );
261 auto plural = this->pluralStr;
262 auto prevFormatter = this->ts.mFormatter;
263 this->ts.mFormatter = [prevFormatter, plural, nn, args...]
264 (const wxString &str, Request request) -> wxString {
265 switch ( request ) {
266 case Request::Context:
267 return TranslatableString::DoGetContext( prevFormatter );
268 case Request::Format:
269 case Request::DebugFormat:
270 default:
271 {
272 bool debug = request == Request::DebugFormat;
273 return wxString::Format(
275 prevFormatter, str, plural, nn, debug ),
277 );
278 }
279 }
280 };
281 return std::move(ts);
282 }
283 };
284
285 wxString mMsgid;
287};
288
291{
292 return std::move(x += std::move(y));
293}
294
295using TranslatableStrings = std::vector<TranslatableString>;
296
298
299namespace std
300{
301 template<> struct hash< TranslatableString > {
302 size_t operator () (const TranslatableString &str) const // noexcept
303 {
304 const wxString &stdstr = str.mMsgid.ToStdWstring(); // no allocations, a cheap fetch
305 using Hasher = hash< wxString >;
306 return Hasher{}( stdstr );
307 }
308 };
309}
310
312template< typename Sink >
313inline Sink &operator <<( Sink &sink, const TranslatableString &str )
314{
315 return sink << str.Translation();
316}
317
319
322{ return TranslatableString( std::move( str ) ); }
323
325inline bool TranslationLess(
326 const TranslatableString &a, const TranslatableString &b)
327{
328 return a.Translation() < b.Translation();
329}
330
331#endif
#define str(a)
ResultType Join(const ContainerType< ResultType, Rest... > &container, const SeparatorType &separator)
Definition: StringUtils.h:52
TranslatableString operator+(TranslatableString x, TranslatableString y)
Sink & operator<<(Sink &sink, const TranslatableString &str)
Allow TranslatableString to work with shift output operators.
bool TranslationLess(const TranslatableString &a, const TranslatableString &b)
A commonly needed sort comparator, which depends on the language setting.
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
bool operator==(const WaveTrackLocation &a, const WaveTrackLocation &b)
bool operator!=(const WaveTrackLocation &a, const WaveTrackLocation &b)
Abstract base class used in importing a file.
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
Class to construct the HTTP request.
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & operator=(const TranslatableString &)=default
static wxString DoChooseFormat(const Formatter &formatter, const wxString &singular, const wxString &plural, unsigned nn, bool debug)
static const wxChar *const NullContextName
std::function< wxString(const wxString &, Request) > Formatter
A multi-purpose function, depending on the enum argument.
wxString DoFormat(bool debug) const
TranslatableString(TranslatableString &&str)
TranslatableString & Context(const wxString &context) &
Choose a non-default and non-null disambiguating context for lookups.
TranslatableString & operator=(TranslatableString &&str)
static const TranslatableString Inaudible
A special string value that will have no screen reader pronunciation.
TranslatableString && Context(const wxString &context) &&
static wxString DoGetContext(const Formatter &formatter)
TranslatableString && Join(TranslatableString arg, const wxString &separator={}) &&
TranslatableString && Strip(unsigned options=MenuCodes) &&
TranslatableString && Format(Args &&...args) &&
static const T & TranslateArgument(const T &arg, bool)
TranslatableString(wxString str)
Construct a TranslatableString that does no translation but passes str verbatim.
TranslatableString & Strip(unsigned options=MenuCodes) &
wxString StrippedTranslation() const
static auto TranslateArgument(const std::reference_wrapper< T > &arg, bool debug) -> decltype(TranslatableString::TranslateArgument(arg.get(), debug))
This allows you to wrap arguments of Format in std::cref.
static wxString DoSubstitute(const Formatter &formatter, const wxString &format, const wxString &context, bool debug)
wxString Translation() const
TranslatableString(const TranslatableString &)=default
PluralTemp< N > Plural(const wxString &pluralStr) &&
Implements the XP macro.
static wxString TranslateArgument(const TranslatableString &arg, bool debug)
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
wxString Debug() const
Format as an English string for debugging logs and developers' eyes, not for end users.
TranslatableString(wxString str, Formatter formatter)
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object
static const Formatter NullContextFormatter
STL namespace.
TranslatableString && operator()(Args &&... args)