mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-23 17:30:17 +01:00
Move TranslatableString to new files
This commit is contained in:
@@ -50,7 +50,7 @@
|
|||||||
#include <wx/debug.h> // for wxASSERT
|
#include <wx/debug.h> // for wxASSERT
|
||||||
#include <wx/string.h> // type used in inline function and member variable
|
#include <wx/string.h> // type used in inline function and member variable
|
||||||
|
|
||||||
#include "../../../src/Identifier.h"
|
#include "../../../src/TranslatableString.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// TODO: I'd imagine this header may be replaced by other public headers. But,
|
// TODO: I'd imagine this header may be replaced by other public headers. But,
|
||||||
@@ -58,310 +58,6 @@
|
|||||||
// until proper public headers are created for the stuff in here.
|
// until proper public headers are created for the stuff in here.
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Holds a msgid for the translation catalog and may hold a closure that
|
|
||||||
// captures formatting arguments
|
|
||||||
//
|
|
||||||
// Different string-valued accessors for the msgid itself, and for the
|
|
||||||
// user-visible translation with substitution of captured format arguments.
|
|
||||||
// Also an accessor for format substitution into the English msgid, for debug-
|
|
||||||
// only outputs.
|
|
||||||
// The msgid should be used only in unusual cases and the translation more often
|
|
||||||
//
|
|
||||||
// Implicit conversions to and from wxString are intentionally disabled
|
|
||||||
class AUDACITY_DLL_API TranslatableString {
|
|
||||||
enum class Request;
|
|
||||||
template< size_t N > struct PluralTemp;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// A special string value that will have no screen reader pronunciation
|
|
||||||
static const TranslatableString Inaudible;
|
|
||||||
|
|
||||||
// A multi-purpose function, depending on the enum argument; the string
|
|
||||||
// argument is unused in some cases
|
|
||||||
// If there is no function, defaults are empty context string, no plurals,
|
|
||||||
// and no substitutions
|
|
||||||
using Formatter = std::function< wxString(const wxString &, Request) >;
|
|
||||||
|
|
||||||
TranslatableString() {}
|
|
||||||
|
|
||||||
// Supply {} for the second argument to cause lookup of the msgid with
|
|
||||||
// empty context string (default context) rather than the null context
|
|
||||||
explicit TranslatableString( wxString str, Formatter formatter )
|
|
||||||
: mFormatter{ std::move(formatter) }
|
|
||||||
{
|
|
||||||
mMsgid.swap( str );
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy and move
|
|
||||||
TranslatableString( const TranslatableString & ) = default;
|
|
||||||
TranslatableString &operator=( const TranslatableString & ) = default;
|
|
||||||
TranslatableString( TranslatableString && str )
|
|
||||||
: mFormatter( std::move( str.mFormatter ) )
|
|
||||||
{
|
|
||||||
mMsgid.swap( str.mMsgid );
|
|
||||||
}
|
|
||||||
TranslatableString &operator=( TranslatableString &&str )
|
|
||||||
{
|
|
||||||
mFormatter = std::move( str.mFormatter );
|
|
||||||
mMsgid.swap( str.mMsgid );
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const { return mMsgid.empty(); }
|
|
||||||
|
|
||||||
// MSGID is the English lookup key in the message catalog, not necessarily
|
|
||||||
// for user's eyes if the locale is some other.
|
|
||||||
// The MSGID might not be all the information TranslatableString holds.
|
|
||||||
// This is a deliberately ugly-looking function name. Use with caution.
|
|
||||||
Identifier MSGID() const { return Identifier{ mMsgid }; }
|
|
||||||
|
|
||||||
wxString Translation() const { return DoFormat( false ); }
|
|
||||||
|
|
||||||
// Format as an English string for debugging logs and developers' eyes, not
|
|
||||||
// for end users
|
|
||||||
wxString Debug() const { return DoFormat( true ); }
|
|
||||||
|
|
||||||
// Warning: comparison of msgids only, which is not all of the information!
|
|
||||||
// This operator makes it easier to define a std::unordered_map on
|
|
||||||
// TranslatableStrings
|
|
||||||
friend bool operator == (
|
|
||||||
const TranslatableString &x, const TranslatableString &y)
|
|
||||||
{ return x.mMsgid == y.mMsgid; }
|
|
||||||
|
|
||||||
friend bool operator != (
|
|
||||||
const TranslatableString &x, const TranslatableString &y)
|
|
||||||
{ return !(x == y); }
|
|
||||||
|
|
||||||
// Returns true if context is NullContextFormatter
|
|
||||||
bool IsVerbatim() const;
|
|
||||||
|
|
||||||
// Capture variadic format arguments (by copy) when there is no plural.
|
|
||||||
// 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, for non-debug formatting
|
|
||||||
template< typename... Args >
|
|
||||||
TranslatableString &Format( Args &&...args ) &
|
|
||||||
{
|
|
||||||
auto prevFormatter = mFormatter;
|
|
||||||
this->mFormatter = [prevFormatter, args...]
|
|
||||||
(const wxString &str, Request request) -> wxString {
|
|
||||||
switch ( request ) {
|
|
||||||
case Request::Context:
|
|
||||||
return TranslatableString::DoGetContext( prevFormatter );
|
|
||||||
case Request::Format:
|
|
||||||
case Request::DebugFormat:
|
|
||||||
default: {
|
|
||||||
bool debug = request == Request::DebugFormat;
|
|
||||||
return wxString::Format(
|
|
||||||
TranslatableString::DoSubstitute(
|
|
||||||
prevFormatter,
|
|
||||||
str, TranslatableString::DoGetContext( prevFormatter ),
|
|
||||||
debug ),
|
|
||||||
TranslatableString::TranslateArgument( args, debug )...
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
template< typename... Args >
|
|
||||||
TranslatableString &&Format( Args &&...args ) &&
|
|
||||||
{
|
|
||||||
return std::move( Format( std::forward<Args>(args)... ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Choose a non-default and non-null disambiguating context for lookups
|
|
||||||
// (but this is not fully implemented)
|
|
||||||
// This is meant to be the first of chain-call modifications of the
|
|
||||||
// TranslatableString object; it will destroy any previously captured
|
|
||||||
// information
|
|
||||||
TranslatableString &Context( const wxString &context ) &
|
|
||||||
{
|
|
||||||
this->mFormatter = [context]
|
|
||||||
(const wxString &str, Request request) -> wxString {
|
|
||||||
switch ( request ) {
|
|
||||||
case Request::Context:
|
|
||||||
return context;
|
|
||||||
case Request::DebugFormat:
|
|
||||||
return DoSubstitute( {}, str, context, true );
|
|
||||||
case Request::Format:
|
|
||||||
default:
|
|
||||||
return DoSubstitute( {}, str, context, false );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
TranslatableString &&Context( const wxString &context ) &&
|
|
||||||
{
|
|
||||||
return std::move( Context( context ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 &Join(
|
|
||||||
TranslatableString arg, const wxString &separator = {} ) &;
|
|
||||||
TranslatableString &&Join(
|
|
||||||
TranslatableString arg, const wxString &separator = {} ) &&
|
|
||||||
{ return std::move( Join( std::move(arg), separator ) ); }
|
|
||||||
|
|
||||||
TranslatableString &operator +=( TranslatableString arg )
|
|
||||||
{
|
|
||||||
Join( std::move( arg ) );
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements the XP macro, which specifies a second msgid, a list
|
|
||||||
// of format arguments, and which of those format arguments selects among
|
|
||||||
// messages; the translated strings to select among, depending on language,
|
|
||||||
// might actually be more or fewer than two. See Internat.h.
|
|
||||||
template< size_t N >
|
|
||||||
PluralTemp< N > Plural( const wxString &pluralStr ) &&
|
|
||||||
{
|
|
||||||
return PluralTemp< N >{ *this, pluralStr };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translated strings may still contain menu hot-key codes (indicated by &)
|
|
||||||
// that wxWidgets interprets, and also trailing ellipses, that should be
|
|
||||||
// removed for other uses.
|
|
||||||
enum StripOptions : unsigned {
|
|
||||||
// Values to be combined with bitwise OR
|
|
||||||
MenuCodes = 0x1,
|
|
||||||
Ellipses = 0x2,
|
|
||||||
};
|
|
||||||
TranslatableString &Strip( unsigned options = MenuCodes ) &;
|
|
||||||
TranslatableString &&Strip( unsigned options = MenuCodes ) &&
|
|
||||||
{ return std::move( Strip( options ) ); }
|
|
||||||
|
|
||||||
// non-mutating, constructs another TranslatableString object
|
|
||||||
TranslatableString Stripped( unsigned options = MenuCodes ) const
|
|
||||||
{ return TranslatableString{ *this }.Strip( options ); }
|
|
||||||
|
|
||||||
wxString StrippedTranslation() const { return Stripped().Translation(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const Formatter NullContextFormatter;
|
|
||||||
|
|
||||||
// Construct a TranslatableString that does no translation but passes
|
|
||||||
// str verbatim
|
|
||||||
explicit TranslatableString( wxString str )
|
|
||||||
: mFormatter{ NullContextFormatter }
|
|
||||||
{
|
|
||||||
mMsgid.swap( str );
|
|
||||||
}
|
|
||||||
|
|
||||||
friend TranslatableString Verbatim( wxString str );
|
|
||||||
|
|
||||||
enum class Request {
|
|
||||||
Context, // return a disambiguating context string
|
|
||||||
Format, // Given the msgid, format the string for end users
|
|
||||||
DebugFormat, // Given the msgid, format the string for developers
|
|
||||||
};
|
|
||||||
|
|
||||||
static const wxChar *const NullContextName;
|
|
||||||
friend std::hash< TranslatableString >;
|
|
||||||
|
|
||||||
static wxString DoGetContext( const Formatter &formatter );
|
|
||||||
static wxString DoSubstitute(
|
|
||||||
const Formatter &formatter,
|
|
||||||
const wxString &format, const wxString &context, bool debug );
|
|
||||||
wxString DoFormat( bool debug ) const
|
|
||||||
{ return DoSubstitute(
|
|
||||||
mFormatter, mMsgid, DoGetContext(mFormatter), debug ); }
|
|
||||||
|
|
||||||
static wxString DoChooseFormat(
|
|
||||||
const Formatter &formatter,
|
|
||||||
const wxString &singular, const wxString &plural, unsigned nn, bool debug );
|
|
||||||
|
|
||||||
template< typename T > static const T &TranslateArgument( const T &arg, bool )
|
|
||||||
{ return arg; }
|
|
||||||
// This allows you to wrap arguments of Format in std::cref so that they
|
|
||||||
// are captured (as if) by reference rather than by value
|
|
||||||
template< typename T > static auto TranslateArgument(
|
|
||||||
const std::reference_wrapper<T> &arg, bool debug )
|
|
||||||
-> decltype(
|
|
||||||
TranslatableString::TranslateArgument( arg.get(), debug ) )
|
|
||||||
{ return TranslatableString::TranslateArgument( arg.get(), debug ); }
|
|
||||||
static wxString TranslateArgument( const TranslatableString &arg, bool debug )
|
|
||||||
{ return arg.DoFormat( debug ); }
|
|
||||||
|
|
||||||
template< size_t N > struct PluralTemp{
|
|
||||||
TranslatableString &ts;
|
|
||||||
const wxString &pluralStr;
|
|
||||||
template< typename... Args >
|
|
||||||
TranslatableString &&operator()( Args&&... args )
|
|
||||||
{
|
|
||||||
// Pick from the pack the argument that specifies number
|
|
||||||
auto selector =
|
|
||||||
std::template get< N >( std::forward_as_tuple( args... ) );
|
|
||||||
// We need an unsigned value. Guard against negative values.
|
|
||||||
auto nn = static_cast<unsigned>(
|
|
||||||
std::max<unsigned long long>( 0, selector )
|
|
||||||
);
|
|
||||||
auto plural = this->pluralStr;
|
|
||||||
auto prevFormatter = this->ts.mFormatter;
|
|
||||||
this->ts.mFormatter = [prevFormatter, plural, nn, args...]
|
|
||||||
(const wxString &str, Request request) -> wxString {
|
|
||||||
switch ( request ) {
|
|
||||||
case Request::Context:
|
|
||||||
return TranslatableString::DoGetContext( prevFormatter );
|
|
||||||
case Request::Format:
|
|
||||||
case Request::DebugFormat:
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
bool debug = request == Request::DebugFormat;
|
|
||||||
return wxString::Format(
|
|
||||||
TranslatableString::DoChooseFormat(
|
|
||||||
prevFormatter, str, plural, nn, debug ),
|
|
||||||
TranslatableString::TranslateArgument( args, debug )...
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return std::move(ts);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
wxString mMsgid;
|
|
||||||
Formatter mFormatter;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline TranslatableString operator +(
|
|
||||||
TranslatableString x, TranslatableString y )
|
|
||||||
{
|
|
||||||
return std::move(x += std::move(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
using TranslatableStrings = std::vector<TranslatableString>;
|
|
||||||
|
|
||||||
// For using std::unordered_map on TranslatableString
|
|
||||||
// Note: hashing on msgids only, which is not all of the information
|
|
||||||
namespace std
|
|
||||||
{
|
|
||||||
template<> struct hash< TranslatableString > {
|
|
||||||
size_t operator () (const TranslatableString &str) const // noexcept
|
|
||||||
{
|
|
||||||
const wxString &stdstr = str.mMsgid.ToStdWstring(); // no allocations, a cheap fetch
|
|
||||||
using Hasher = hash< wxString >;
|
|
||||||
return Hasher{}( stdstr );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow TranslatableString to work with shift output operators
|
|
||||||
template< typename Sink >
|
|
||||||
inline Sink &operator <<( Sink &sink, const TranslatableString &str )
|
|
||||||
{
|
|
||||||
return sink << str.Translation();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Require calls to the one-argument constructor to go through this
|
|
||||||
// distinct global function name. This makes it easier to locate and
|
|
||||||
// review the uses of this function, separately from the uses of the type.
|
|
||||||
inline TranslatableString Verbatim( wxString str )
|
|
||||||
{ return TranslatableString( std::move( str ) ); }
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// A native 64-bit integer...used when referring to any number of samples
|
// A native 64-bit integer...used when referring to any number of samples
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -326,6 +326,8 @@ list( APPEND SOURCES
|
|||||||
TrackPanelResizerCell.h
|
TrackPanelResizerCell.h
|
||||||
TrackUtilities.cpp
|
TrackUtilities.cpp
|
||||||
TrackUtilities.h
|
TrackUtilities.h
|
||||||
|
TranslatableString.cpp
|
||||||
|
TranslatableString.h
|
||||||
UIHandle.cpp
|
UIHandle.cpp
|
||||||
UIHandle.h
|
UIHandle.h
|
||||||
UndoManager.cpp
|
UndoManager.cpp
|
||||||
|
|||||||
134
src/Internat.cpp
134
src/Internat.cpp
@@ -258,137 +258,3 @@ bool Internat::SanitiseFilename(wxString &name, const wxString &sub)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxChar *const TranslatableString::NullContextName = wxT("*");
|
|
||||||
|
|
||||||
const TranslatableString::Formatter
|
|
||||||
TranslatableString::NullContextFormatter {
|
|
||||||
[](const wxString & str, TranslatableString::Request request) -> wxString {
|
|
||||||
switch ( request ) {
|
|
||||||
case Request::Context:
|
|
||||||
return NullContextName;
|
|
||||||
case Request::Format:
|
|
||||||
case Request::DebugFormat:
|
|
||||||
default:
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool TranslatableString::IsVerbatim() const
|
|
||||||
{
|
|
||||||
return DoGetContext( mFormatter ) == NullContextName;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslatableString &TranslatableString::Strip( unsigned codes ) &
|
|
||||||
{
|
|
||||||
auto prevFormatter = mFormatter;
|
|
||||||
mFormatter = [prevFormatter, codes]
|
|
||||||
( const wxString & str, TranslatableString::Request request ) -> wxString {
|
|
||||||
switch ( request ) {
|
|
||||||
case Request::Context:
|
|
||||||
return TranslatableString::DoGetContext( prevFormatter );
|
|
||||||
case Request::Format:
|
|
||||||
case Request::DebugFormat:
|
|
||||||
default: {
|
|
||||||
bool debug = request == Request::DebugFormat;
|
|
||||||
auto result =
|
|
||||||
TranslatableString::DoSubstitute(
|
|
||||||
prevFormatter,
|
|
||||||
str, TranslatableString::DoGetContext( prevFormatter ),
|
|
||||||
debug );
|
|
||||||
if ( codes & MenuCodes ) {
|
|
||||||
// Don't use this, it's in wxCore
|
|
||||||
// result = wxStripMenuCodes( result );
|
|
||||||
decltype( result ) temp;
|
|
||||||
temp.swap(result);
|
|
||||||
for ( auto iter = temp.begin(), end = temp.end();
|
|
||||||
iter != end; ++iter ) {
|
|
||||||
// Stop at trailing hot key name
|
|
||||||
if ( *iter == '\t' )
|
|
||||||
break;
|
|
||||||
// Strip & (unless escaped by another preceding &)
|
|
||||||
if ( *iter == '&' && ++iter == end )
|
|
||||||
break;
|
|
||||||
result.append( 1, *iter );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( codes & Ellipses ) {
|
|
||||||
if (result.EndsWith(wxT("...")))
|
|
||||||
result = result.Left( result.length() - 3 );
|
|
||||||
// Also check for the single-character Unicode ellipsis
|
|
||||||
else if (result.EndsWith(wxT("\u2026")))
|
|
||||||
result = result.Left( result.length() - 1 );
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString TranslatableString::DoGetContext( const Formatter &formatter )
|
|
||||||
{
|
|
||||||
return formatter ? formatter( {}, Request::Context ) : wxString{};
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString TranslatableString::DoSubstitute( const Formatter &formatter,
|
|
||||||
const wxString &format, const wxString &context, bool debug )
|
|
||||||
{
|
|
||||||
return formatter
|
|
||||||
? formatter( format, debug ? Request::DebugFormat : Request::Format )
|
|
||||||
: // come here for most translatable strings, which have no formatting
|
|
||||||
( debug ? format : wxGetTranslation( format, wxString{}, context ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString TranslatableString::DoChooseFormat(
|
|
||||||
const Formatter &formatter,
|
|
||||||
const wxString &singular, const wxString &plural, unsigned nn, bool debug )
|
|
||||||
{
|
|
||||||
// come here for translatable strings that choose among forms by number;
|
|
||||||
// if not debugging, then two keys are passed to an overload of
|
|
||||||
// wxGetTranslation, and also a number.
|
|
||||||
// Some languages might choose among more or fewer than two forms
|
|
||||||
// (e.g. Arabic has duals and Russian has complicated declension rules)
|
|
||||||
wxString context;
|
|
||||||
return ( debug || NullContextName == (context = DoGetContext(formatter)) )
|
|
||||||
? ( nn == 1 ? singular : plural )
|
|
||||||
: wxGetTranslation(
|
|
||||||
singular, plural, nn
|
|
||||||
#if HAS_I18N_CONTEXTS
|
|
||||||
, wxString{} // domain
|
|
||||||
, context
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslatableString &TranslatableString::Join(
|
|
||||||
const TranslatableString arg, const wxString &separator ) &
|
|
||||||
{
|
|
||||||
auto prevFormatter = mFormatter;
|
|
||||||
mFormatter =
|
|
||||||
[prevFormatter,
|
|
||||||
arg /* = std::move( arg ) */,
|
|
||||||
separator](const wxString &str, Request request)
|
|
||||||
-> wxString {
|
|
||||||
switch ( request ) {
|
|
||||||
case Request::Context:
|
|
||||||
return TranslatableString::DoGetContext( prevFormatter );
|
|
||||||
case Request::Format:
|
|
||||||
case Request::DebugFormat:
|
|
||||||
default: {
|
|
||||||
bool debug = request == Request::DebugFormat;
|
|
||||||
return
|
|
||||||
TranslatableString::DoSubstitute( prevFormatter,
|
|
||||||
str, TranslatableString::DoGetContext( prevFormatter ),
|
|
||||||
debug )
|
|
||||||
+ separator
|
|
||||||
+ arg.DoFormat( debug );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TranslatableString TranslatableString::Inaudible{ wxT("\a") };
|
|
||||||
|
|||||||
@@ -2,262 +2,14 @@
|
|||||||
|
|
||||||
Audacity: A Digital Audio Editor
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
Internat.cpp
|
@file TranslatableString.cpp
|
||||||
|
|
||||||
Markus Meyer
|
Paul Licameli split from Internat.cpp
|
||||||
Dominic Mazzoni (Mac OS X code)
|
|
||||||
|
|
||||||
*******************************************************************//*!
|
**********************************************************************/
|
||||||
|
|
||||||
\class Internat
|
#include "TranslatableString.h"
|
||||||
\brief Internationalisation support.
|
#include <wx/translation.h>
|
||||||
|
|
||||||
This class is used to help internationalisation and in general
|
|
||||||
compatibility with different locales and character sets.
|
|
||||||
It deals mostly with converting numbers, but also has important
|
|
||||||
functions to convert to/from UTF-8, which is used in XML files
|
|
||||||
and on Mac OS X for the filesystem.
|
|
||||||
|
|
||||||
*//*******************************************************************/
|
|
||||||
|
|
||||||
#include "Internat.h"
|
|
||||||
|
|
||||||
#include <wx/log.h>
|
|
||||||
#include <wx/intl.h>
|
|
||||||
#include <wx/filename.h>
|
|
||||||
|
|
||||||
#include <locale.h>
|
|
||||||
#include <math.h> // for pow()
|
|
||||||
|
|
||||||
// in order for the static member variables to exist, they must appear here
|
|
||||||
// (_outside_) the class definition, in order to be allocated some storage.
|
|
||||||
// Otherwise, you get link errors.
|
|
||||||
|
|
||||||
wxChar Internat::mDecimalSeparator = wxT('.'); // default
|
|
||||||
// exclude is used by SanitiseFilename.
|
|
||||||
wxArrayString Internat::exclude;
|
|
||||||
|
|
||||||
// DA: Use tweaked translation mechanism to replace 'Audacity' by 'DarkAudacity'.
|
|
||||||
#ifdef EXPERIMENTAL_DA
|
|
||||||
// This function allows us to replace Audacity by DarkAudacity without peppering
|
|
||||||
// the source code with changes. We split out this step, the customisation, as
|
|
||||||
// it is used on its own (without translation) in the wxTS macro.
|
|
||||||
AUDACITY_DLL_API const wxString& GetCustomSubstitution(const wxString& str2)
|
|
||||||
{
|
|
||||||
// If contains 'DarkAudacity, already converted.
|
|
||||||
if( str2.Contains( "DarkAudacity" ))
|
|
||||||
return str2;
|
|
||||||
// If does not contain 'Audacity', nothing to do.
|
|
||||||
if( !str2.Contains( "Audacity" ))
|
|
||||||
return str2;
|
|
||||||
wxString str3 = str2;
|
|
||||||
str3.Replace( "Audacity", "DarkAudacity" );
|
|
||||||
str3.Replace( " an DarkAudacity", " a DarkAudacity" );
|
|
||||||
// DA also renames sync-lock(ed) as time-lock(ed).
|
|
||||||
str3.Replace( "Sync-Lock", "Time-Lock" );
|
|
||||||
str3.Replace( "Sync-&Lock", "Time-&Lock" );
|
|
||||||
str3.Replace( "Sync Lock", "Time Lock" );
|
|
||||||
return wxTranslations::GetUntranslatedString(str3);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
AUDACITY_DLL_API const wxString& GetCustomSubstitution(const wxString& str1)
|
|
||||||
{
|
|
||||||
return str1 ;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// In any translated string, we can replace the name 'Audacity' by 'DarkAudacity'
|
|
||||||
// without requiring translators to see extra strings for the two versions.
|
|
||||||
AUDACITY_DLL_API const wxString& GetCustomTranslation(const wxString& str1)
|
|
||||||
{
|
|
||||||
const wxString& str2 = wxGetTranslation( str1 );
|
|
||||||
return GetCustomSubstitution( str2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Internat::Init()
|
|
||||||
{
|
|
||||||
// Save decimal point character
|
|
||||||
struct lconv * localeInfo = localeconv();
|
|
||||||
if (localeInfo)
|
|
||||||
mDecimalSeparator = wxString(wxSafeConvertMB2WX(localeInfo->decimal_point)).GetChar(0);
|
|
||||||
|
|
||||||
// wxLogDebug(wxT("Decimal separator set to '%c'"), mDecimalSeparator);
|
|
||||||
|
|
||||||
// Setup list of characters that aren't allowed in file names
|
|
||||||
// Hey! The default wxPATH_NATIVE does not do as it should.
|
|
||||||
#if defined(__WXMAC__)
|
|
||||||
wxPathFormat format = wxPATH_MAC;
|
|
||||||
#elif defined(__WXGTK__)
|
|
||||||
wxPathFormat format = wxPATH_UNIX;
|
|
||||||
#elif defined(__WXMSW__)
|
|
||||||
wxPathFormat format = wxPATH_WIN;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This is supposed to return characters not permitted in paths to files
|
|
||||||
// or to directories
|
|
||||||
auto forbid = wxFileName::GetForbiddenChars(format);
|
|
||||||
|
|
||||||
for (auto cc: forbid) {
|
|
||||||
#if defined(__WXGTK__)
|
|
||||||
if (cc == wxT('*') || cc == wxT('?')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
exclude.push_back(wxString{ cc });
|
|
||||||
}
|
|
||||||
|
|
||||||
// The path separators may not be forbidden, so add them
|
|
||||||
//auto separators = wxFileName::GetPathSeparators(format);
|
|
||||||
|
|
||||||
// Bug 1441 exclude all separators from filenames on all platforms.
|
|
||||||
auto separators = wxString("\\/");
|
|
||||||
|
|
||||||
for(auto cc: separators) {
|
|
||||||
if (forbid.Find(cc) == wxNOT_FOUND)
|
|
||||||
exclude.push_back(wxString{ cc });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Internat::SetCeeNumberFormat()
|
|
||||||
{
|
|
||||||
wxSetlocale( LC_NUMERIC, "C" );
|
|
||||||
mDecimalSeparator = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
wxChar Internat::GetDecimalSeparator()
|
|
||||||
{
|
|
||||||
return mDecimalSeparator;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Internat::CompatibleToDouble(const wxString& stringToConvert, double* result)
|
|
||||||
{
|
|
||||||
// Regardless of the locale, always respect comma _and_ point
|
|
||||||
wxString s = stringToConvert;
|
|
||||||
s.Replace(wxT(","), wxString(GetDecimalSeparator()));
|
|
||||||
s.Replace(wxT("."), wxString(GetDecimalSeparator()));
|
|
||||||
return s.ToDouble(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Internat::CompatibleToDouble(const wxString& stringToConvert)
|
|
||||||
{
|
|
||||||
double result = 0;
|
|
||||||
Internat::CompatibleToDouble(stringToConvert, &result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString Internat::ToString(double numberToConvert,
|
|
||||||
int digitsAfterDecimalPoint /* = -1 */)
|
|
||||||
{
|
|
||||||
wxString result = ToDisplayString(
|
|
||||||
numberToConvert, digitsAfterDecimalPoint);
|
|
||||||
|
|
||||||
result.Replace(wxString(GetDecimalSeparator()), wxT("."));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString Internat::ToDisplayString(double numberToConvert,
|
|
||||||
int digitsAfterDecimalPoint /* = -1 */)
|
|
||||||
{
|
|
||||||
wxString decSep = wxString(GetDecimalSeparator());
|
|
||||||
wxString result;
|
|
||||||
|
|
||||||
if (digitsAfterDecimalPoint == -1)
|
|
||||||
{
|
|
||||||
result.Printf(wxT("%f"), numberToConvert);
|
|
||||||
|
|
||||||
// Not all libcs respect the decimal separator, so always convert
|
|
||||||
// any dots found to the decimal separator.
|
|
||||||
result.Replace(wxT("."), decSep);
|
|
||||||
|
|
||||||
if (result.Find(decSep) != -1)
|
|
||||||
{
|
|
||||||
// Strip trailing zeros, but leave one, and decimal separator.
|
|
||||||
int pos = result.length() - 1;
|
|
||||||
while ((pos > 1) &&
|
|
||||||
(result.GetChar(pos) == wxT('0')) &&
|
|
||||||
(result.GetChar(pos - 1) != decSep))
|
|
||||||
pos--;
|
|
||||||
// (Previous code removed all of them and decimal separator.)
|
|
||||||
// if (result.GetChar(pos) == decSep)
|
|
||||||
// pos--; // strip point before empty fractional part
|
|
||||||
result = result.Left(pos+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wxString format;
|
|
||||||
format.Printf(wxT("%%.%if"), digitsAfterDecimalPoint);
|
|
||||||
result.Printf(format, numberToConvert);
|
|
||||||
|
|
||||||
// Not all libcs respect the decimal separator, so always convert
|
|
||||||
// any dots found to the decimal separator
|
|
||||||
result.Replace(wxT("."), decSep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslatableString Internat::FormatSize(wxLongLong size)
|
|
||||||
{
|
|
||||||
/* wxLongLong contains no built-in conversion to double */
|
|
||||||
double dSize = size.GetHi() * pow(2.0, 32); // 2 ^ 32
|
|
||||||
dSize += size.GetLo();
|
|
||||||
|
|
||||||
return FormatSize(dSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslatableString Internat::FormatSize(double size)
|
|
||||||
{
|
|
||||||
TranslatableString sizeStr;
|
|
||||||
|
|
||||||
if (size == -1)
|
|
||||||
sizeStr = XO("Unable to determine");
|
|
||||||
else {
|
|
||||||
/* make it look nice, by formatting into k, MB, etc */
|
|
||||||
if (size < 1024.0)
|
|
||||||
sizeStr = XO("%s bytes").Format( ToDisplayString(size) );
|
|
||||||
else if (size < 1024.0 * 1024.0) {
|
|
||||||
/* i18n-hint: Abbreviation for Kilo bytes */
|
|
||||||
sizeStr = XO("%s KB").Format( ToDisplayString(size / 1024.0, 1) );
|
|
||||||
}
|
|
||||||
else if (size < 1024.0 * 1024.0 * 1024.0) {
|
|
||||||
/* i18n-hint: Abbreviation for Mega bytes */
|
|
||||||
sizeStr = XO("%s MB").Format( ToDisplayString(size / (1024.0 * 1024.0), 1) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* i18n-hint: Abbreviation for Giga bytes */
|
|
||||||
sizeStr = XO("%s GB").Format( ToDisplayString(size / (1024.0 * 1024.0 * 1024.0), 1) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sizeStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Internat::SanitiseFilename(wxString &name, const wxString &sub)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
for(const auto &item : exclude)
|
|
||||||
{
|
|
||||||
if(name.Contains(item))
|
|
||||||
{
|
|
||||||
name.Replace(item, sub);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __WXMAC__
|
|
||||||
// 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 substitution.
|
|
||||||
name.Replace(wxT("/"), wxT(":"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wxChar *const TranslatableString::NullContextName = wxT("*");
|
const wxChar *const TranslatableString::NullContextName = wxT("*");
|
||||||
|
|
||||||
|
|||||||
@@ -2,90 +2,48 @@
|
|||||||
|
|
||||||
Audacity: A Digital Audio Editor
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
Types.h
|
@file TranslatableString.h
|
||||||
|
|
||||||
Leland Lucius
|
Paul Licameli split from Types.h
|
||||||
|
|
||||||
Copyright (c) 2014, Audacity Team
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#ifndef __AUDACITY_TYPES_H__
|
#ifndef __AUDACITY_TRANSLATABLE_STRING__
|
||||||
#define __AUDACITY_TYPES_H__
|
#define __AUDACITY_TRANSLATABLE_STRING__
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
#include <limits>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <vector>
|
|
||||||
#include <wx/debug.h> // for wxASSERT
|
|
||||||
#include <wx/string.h> // type used in inline function and member variable
|
|
||||||
|
|
||||||
#include "../../../src/Identifier.h"
|
#include "../../../src/Identifier.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
#include <vector>
|
||||||
// TODO: I'd imagine this header may be replaced by other public headers. But,
|
|
||||||
// to try and minimize more changes to the base code, we can use this
|
|
||||||
// until proper public headers are created for the stuff in here.
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Holds a msgid for the translation catalog and may hold a closure that
|
//! Holds a msgid for the translation catalog; may also bind format arguments
|
||||||
// captures formatting arguments
|
/*!
|
||||||
//
|
Different string-valued accessors for the msgid itself, and for the
|
||||||
// Different string-valued accessors for the msgid itself, and for the
|
user-visible translation with substitution of captured format arguments.
|
||||||
// user-visible translation with substitution of captured format arguments.
|
Also an accessor for format substitution into the English msgid, for debug-
|
||||||
// Also an accessor for format substitution into the English msgid, for debug-
|
only outputs.
|
||||||
// only outputs.
|
The msgid should be used only in unusual cases and the translation more often
|
||||||
// The msgid should be used only in unusual cases and the translation more often
|
|
||||||
//
|
Implicit conversions to and from wxString are intentionally disabled
|
||||||
// Implicit conversions to and from wxString are intentionally disabled
|
*/
|
||||||
class AUDACITY_DLL_API TranslatableString {
|
class AUDACITY_DLL_API TranslatableString {
|
||||||
enum class Request;
|
enum class Request;
|
||||||
template< size_t N > struct PluralTemp;
|
template< size_t N > struct PluralTemp;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// A special string value that will have no screen reader pronunciation
|
//! A special string value that will have no screen reader pronunciation
|
||||||
static const TranslatableString Inaudible;
|
static const TranslatableString Inaudible;
|
||||||
|
|
||||||
// A multi-purpose function, depending on the enum argument; the string
|
//! A multi-purpose function, depending on the enum argument
|
||||||
// argument is unused in some cases
|
/*! the string
|
||||||
// If there is no function, defaults are empty context string, no plurals,
|
argument is unused in some cases
|
||||||
// and no substitutions
|
If there is no function, defaults are empty context string, no plurals,
|
||||||
|
and no substitutions */
|
||||||
using Formatter = std::function< wxString(const wxString &, Request) >;
|
using Formatter = std::function< wxString(const wxString &, Request) >;
|
||||||
|
|
||||||
TranslatableString() {}
|
TranslatableString() {}
|
||||||
|
|
||||||
// Supply {} for the second argument to cause lookup of the msgid with
|
/*! Supply {} for the second argument to cause lookup of the msgid with
|
||||||
// empty context string (default context) rather than the null context
|
empty context string (default context) rather than the null context */
|
||||||
explicit TranslatableString( wxString str, Formatter formatter )
|
explicit TranslatableString( wxString str, Formatter formatter )
|
||||||
: mFormatter{ std::move(formatter) }
|
: mFormatter{ std::move(formatter) }
|
||||||
{
|
{
|
||||||
@@ -109,21 +67,18 @@ public:
|
|||||||
|
|
||||||
bool empty() const { return mMsgid.empty(); }
|
bool empty() const { return mMsgid.empty(); }
|
||||||
|
|
||||||
// MSGID is the English lookup key in the message catalog, not necessarily
|
//! MSGID is the English lookup key in the catalog, not necessarily for user's eyes if locale is some other.
|
||||||
// for user's eyes if the locale is some other.
|
/*! The MSGID might not be all the information TranslatableString holds.
|
||||||
// The MSGID might not be all the information TranslatableString holds.
|
This is a deliberately ugly-looking function name. Use with caution. */
|
||||||
// This is a deliberately ugly-looking function name. Use with caution.
|
|
||||||
Identifier MSGID() const { return Identifier{ mMsgid }; }
|
Identifier MSGID() const { return Identifier{ mMsgid }; }
|
||||||
|
|
||||||
wxString Translation() const { return DoFormat( false ); }
|
wxString Translation() const { return DoFormat( false ); }
|
||||||
|
|
||||||
// Format as an English string for debugging logs and developers' eyes, not
|
//! Format as an English string for debugging logs and developers' eyes, not for end users
|
||||||
// for end users
|
|
||||||
wxString Debug() const { return DoFormat( true ); }
|
wxString Debug() const { return DoFormat( true ); }
|
||||||
|
|
||||||
// Warning: comparison of msgids only, which is not all of the information!
|
//! Warning: comparison of msgids only, which is not all of the information!
|
||||||
// This operator makes it easier to define a std::unordered_map on
|
/*! This operator makes it easier to define a std::unordered_map on TranslatableStrings */
|
||||||
// TranslatableStrings
|
|
||||||
friend bool operator == (
|
friend bool operator == (
|
||||||
const TranslatableString &x, const TranslatableString &y)
|
const TranslatableString &x, const TranslatableString &y)
|
||||||
{ return x.mMsgid == y.mMsgid; }
|
{ return x.mMsgid == y.mMsgid; }
|
||||||
@@ -132,14 +87,14 @@ public:
|
|||||||
const TranslatableString &x, const TranslatableString &y)
|
const TranslatableString &x, const TranslatableString &y)
|
||||||
{ return !(x == y); }
|
{ return !(x == y); }
|
||||||
|
|
||||||
// Returns true if context is NullContextFormatter
|
//! Returns true if context is NullContextFormatter
|
||||||
bool IsVerbatim() const;
|
bool IsVerbatim() const;
|
||||||
|
|
||||||
// Capture variadic format arguments (by copy) when there is no plural.
|
//! Capture variadic format arguments (by copy) when there is no plural.
|
||||||
// The substitution is computed later in a call to Translate() after msgid is
|
/*! The substitution is computed later in a call to Translate() after msgid is
|
||||||
// looked up in the translation catalog.
|
looked up in the translation catalog.
|
||||||
// Any format arguments that are also of type TranslatableString will be
|
Any format arguments that are also of type TranslatableString will be
|
||||||
// translated too at substitution time, for non-debug formatting
|
translated too at substitution time, for non-debug formatting */
|
||||||
template< typename... Args >
|
template< typename... Args >
|
||||||
TranslatableString &Format( Args &&...args ) &
|
TranslatableString &Format( Args &&...args ) &
|
||||||
{
|
{
|
||||||
@@ -171,11 +126,10 @@ public:
|
|||||||
return std::move( Format( std::forward<Args>(args)... ) );
|
return std::move( Format( std::forward<Args>(args)... ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose a non-default and non-null disambiguating context for lookups
|
//! Choose a non-default and non-null disambiguating context for lookups
|
||||||
// (but this is not fully implemented)
|
/*! This is meant to be the first of chain-call modifications of the
|
||||||
// This is meant to be the first of chain-call modifications of the
|
TranslatableString object; it will destroy any previously captured
|
||||||
// TranslatableString object; it will destroy any previously captured
|
information */
|
||||||
// information
|
|
||||||
TranslatableString &Context( const wxString &context ) &
|
TranslatableString &Context( const wxString &context ) &
|
||||||
{
|
{
|
||||||
this->mFormatter = [context]
|
this->mFormatter = [context]
|
||||||
@@ -197,9 +151,10 @@ public:
|
|||||||
return std::move( Context( context ) );
|
return std::move( Context( context ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append another translatable string; lookup of msgids for
|
//! Append another translatable string
|
||||||
// this and for the argument are both delayed until Translate() is invoked
|
/*! lookup of msgids for
|
||||||
// on this, and then the formatter concatenates the translations
|
this and for the argument are both delayed until Translate() is invoked
|
||||||
|
on this, and then the formatter concatenates the translations */
|
||||||
TranslatableString &Join(
|
TranslatableString &Join(
|
||||||
TranslatableString arg, const wxString &separator = {} ) &;
|
TranslatableString arg, const wxString &separator = {} ) &;
|
||||||
TranslatableString &&Join(
|
TranslatableString &&Join(
|
||||||
@@ -212,19 +167,20 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements the XP macro, which specifies a second msgid, a list
|
//! Implements the XP macro
|
||||||
// of format arguments, and which of those format arguments selects among
|
/*! That macro specifies a second msgid, a list
|
||||||
// messages; the translated strings to select among, depending on language,
|
of format arguments, and which of those format arguments selects among
|
||||||
// might actually be more or fewer than two. See Internat.h.
|
messages; the translated strings to select among, depending on language,
|
||||||
|
might actually be more or fewer than two. See Internat.h. */
|
||||||
template< size_t N >
|
template< size_t N >
|
||||||
PluralTemp< N > Plural( const wxString &pluralStr ) &&
|
PluralTemp< N > Plural( const wxString &pluralStr ) &&
|
||||||
{
|
{
|
||||||
return PluralTemp< N >{ *this, pluralStr };
|
return PluralTemp< N >{ *this, pluralStr };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translated strings may still contain menu hot-key codes (indicated by &)
|
/*! Translated strings may still contain menu hot-key codes (indicated by &)
|
||||||
// that wxWidgets interprets, and also trailing ellipses, that should be
|
that wxWidgets interprets, and also trailing ellipses, that should be
|
||||||
// removed for other uses.
|
removed for other uses. */
|
||||||
enum StripOptions : unsigned {
|
enum StripOptions : unsigned {
|
||||||
// Values to be combined with bitwise OR
|
// Values to be combined with bitwise OR
|
||||||
MenuCodes = 0x1,
|
MenuCodes = 0x1,
|
||||||
@@ -234,7 +190,7 @@ public:
|
|||||||
TranslatableString &&Strip( unsigned options = MenuCodes ) &&
|
TranslatableString &&Strip( unsigned options = MenuCodes ) &&
|
||||||
{ return std::move( Strip( options ) ); }
|
{ return std::move( Strip( options ) ); }
|
||||||
|
|
||||||
// non-mutating, constructs another TranslatableString object
|
//! non-mutating, constructs another TranslatableString object
|
||||||
TranslatableString Stripped( unsigned options = MenuCodes ) const
|
TranslatableString Stripped( unsigned options = MenuCodes ) const
|
||||||
{ return TranslatableString{ *this }.Strip( options ); }
|
{ return TranslatableString{ *this }.Strip( options ); }
|
||||||
|
|
||||||
@@ -243,8 +199,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
static const Formatter NullContextFormatter;
|
static const Formatter NullContextFormatter;
|
||||||
|
|
||||||
// Construct a TranslatableString that does no translation but passes
|
//! Construct a TranslatableString that does no translation but passes str verbatim
|
||||||
// str verbatim
|
|
||||||
explicit TranslatableString( wxString str )
|
explicit TranslatableString( wxString str )
|
||||||
: mFormatter{ NullContextFormatter }
|
: mFormatter{ NullContextFormatter }
|
||||||
{
|
{
|
||||||
@@ -254,9 +209,9 @@ private:
|
|||||||
friend TranslatableString Verbatim( wxString str );
|
friend TranslatableString Verbatim( wxString str );
|
||||||
|
|
||||||
enum class Request {
|
enum class Request {
|
||||||
Context, // return a disambiguating context string
|
Context, //!< return a disambiguating context string
|
||||||
Format, // Given the msgid, format the string for end users
|
Format, //!< Given the msgid, format the string for end users
|
||||||
DebugFormat, // Given the msgid, format the string for developers
|
DebugFormat, //!< Given the msgid, format the string for developers
|
||||||
};
|
};
|
||||||
|
|
||||||
static const wxChar *const NullContextName;
|
static const wxChar *const NullContextName;
|
||||||
@@ -276,8 +231,8 @@ private:
|
|||||||
|
|
||||||
template< typename T > static const T &TranslateArgument( const T &arg, bool )
|
template< typename T > static const T &TranslateArgument( const T &arg, bool )
|
||||||
{ return arg; }
|
{ return arg; }
|
||||||
// This allows you to wrap arguments of Format in std::cref so that they
|
//! This allows you to wrap arguments of Format in std::cref
|
||||||
// are captured (as if) by reference rather than by value
|
/*! (So that they are captured (as if) by reference rather than by value) */
|
||||||
template< typename T > static auto TranslateArgument(
|
template< typename T > static auto TranslateArgument(
|
||||||
const std::reference_wrapper<T> &arg, bool debug )
|
const std::reference_wrapper<T> &arg, bool debug )
|
||||||
-> decltype(
|
-> decltype(
|
||||||
@@ -335,8 +290,8 @@ inline TranslatableString operator +(
|
|||||||
|
|
||||||
using TranslatableStrings = std::vector<TranslatableString>;
|
using TranslatableStrings = std::vector<TranslatableString>;
|
||||||
|
|
||||||
// For using std::unordered_map on TranslatableString
|
//! For using std::unordered_map on TranslatableString
|
||||||
// Note: hashing on msgids only, which is not all of the information
|
/*! Note: hashing on msgids only, which is not all of the information */
|
||||||
namespace std
|
namespace std
|
||||||
{
|
{
|
||||||
template<> struct hash< TranslatableString > {
|
template<> struct hash< TranslatableString > {
|
||||||
@@ -349,228 +304,17 @@ namespace std
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow TranslatableString to work with shift output operators
|
//! Allow TranslatableString to work with shift output operators
|
||||||
template< typename Sink >
|
template< typename Sink >
|
||||||
inline Sink &operator <<( Sink &sink, const TranslatableString &str )
|
inline Sink &operator <<( Sink &sink, const TranslatableString &str )
|
||||||
{
|
{
|
||||||
return sink << str.Translation();
|
return sink << str.Translation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Require calls to the one-argument constructor to go through this
|
//! Require calls to the one-argument constructor to go through this distinct global function name.
|
||||||
// distinct global function name. This makes it easier to locate and
|
/*! This makes it easier to locate and
|
||||||
// review the uses of this function, separately from the uses of the type.
|
review the uses of this function, separately from the uses of the type. */
|
||||||
inline TranslatableString Verbatim( wxString str )
|
inline TranslatableString Verbatim( wxString str )
|
||||||
{ return TranslatableString( std::move( str ) ); }
|
{ return TranslatableString( std::move( str ) ); }
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
#endif
|
||||||
// A native 64-bit integer...used when referring to any number of samples
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class sampleCount
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using type = long long;
|
|
||||||
static_assert(sizeof(type) == 8, "Wrong width of sampleCount");
|
|
||||||
|
|
||||||
sampleCount () : value { 0 } {}
|
|
||||||
|
|
||||||
// Allow implicit conversion from integral types
|
|
||||||
sampleCount ( type v ) : value { v } {}
|
|
||||||
sampleCount ( unsigned long long v ) : value ( v ) {}
|
|
||||||
sampleCount ( int v ) : value { v } {}
|
|
||||||
sampleCount ( unsigned v ) : value { v } {}
|
|
||||||
sampleCount ( long v ) : value { v } {}
|
|
||||||
|
|
||||||
// unsigned long is 64 bit on some platforms. Let it narrow.
|
|
||||||
sampleCount ( unsigned long v ) : value ( v ) {}
|
|
||||||
|
|
||||||
// Beware implicit conversions from floating point values!
|
|
||||||
// Otherwise the meaning of binary operators with sampleCount change
|
|
||||||
// their meaning when sampleCount is not an alias!
|
|
||||||
explicit sampleCount ( float f ) : value ( f ) {}
|
|
||||||
explicit sampleCount ( double d ) : value ( d ) {}
|
|
||||||
|
|
||||||
sampleCount ( const sampleCount& ) = default;
|
|
||||||
sampleCount &operator= ( const sampleCount& ) = default;
|
|
||||||
|
|
||||||
float as_float() const { return value; }
|
|
||||||
double as_double() const { return value; }
|
|
||||||
|
|
||||||
long long as_long_long() const { return value; }
|
|
||||||
|
|
||||||
size_t as_size_t() const {
|
|
||||||
wxASSERT(value >= 0);
|
|
||||||
wxASSERT(static_cast<std::make_unsigned<type>::type>(value) <= std::numeric_limits<size_t>::max());
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
sampleCount &operator += (sampleCount b) { value += b.value; return *this; }
|
|
||||||
sampleCount &operator -= (sampleCount b) { value -= b.value; return *this; }
|
|
||||||
sampleCount &operator *= (sampleCount b) { value *= b.value; return *this; }
|
|
||||||
sampleCount &operator /= (sampleCount b) { value /= b.value; return *this; }
|
|
||||||
sampleCount &operator %= (sampleCount b) { value %= b.value; return *this; }
|
|
||||||
|
|
||||||
sampleCount operator - () const { return -value; }
|
|
||||||
|
|
||||||
sampleCount &operator ++ () { ++value; return *this; }
|
|
||||||
sampleCount operator ++ (int)
|
|
||||||
{ sampleCount result{ *this }; ++value; return result; }
|
|
||||||
|
|
||||||
sampleCount &operator -- () { --value; return *this; }
|
|
||||||
sampleCount operator -- (int)
|
|
||||||
{ sampleCount result{ *this }; --value; return result; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
type value;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool operator == (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return a.as_long_long() == b.as_long_long();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator != (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator < (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return a.as_long_long() < b.as_long_long();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator >= (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return !(a < b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator > (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return b < a;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator <= (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return !(b < a);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline sampleCount operator + (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return sampleCount{ a } += b;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline sampleCount operator - (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return sampleCount{ a } -= b;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline sampleCount operator * (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return sampleCount{ a } *= b;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline sampleCount operator / (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return sampleCount{ a } /= b;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline sampleCount operator % (sampleCount a, sampleCount b)
|
|
||||||
{
|
|
||||||
return sampleCount{ a } %= b;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Function returning the minimum of a sampleCount and a size_t,
|
|
||||||
// hiding the casts
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
inline size_t limitSampleBufferSize( size_t bufferSize, sampleCount limit )
|
|
||||||
{
|
|
||||||
return
|
|
||||||
std::min( sampleCount( bufferSize ), std::max( sampleCount(0), limit ) )
|
|
||||||
.as_size_t();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Supported sample formats
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
enum sampleFormat : unsigned
|
|
||||||
{
|
|
||||||
//! The increasing sequence of these enum values must correspond to the increasing data type width
|
|
||||||
//! These values persist in saved project files, so must not be changed in later program versions
|
|
||||||
int16Sample = 0x00020001,
|
|
||||||
int24Sample = 0x00040001,
|
|
||||||
floatSample = 0x0004000F,
|
|
||||||
|
|
||||||
//! Two synonyms for previous values that might change if more values were added
|
|
||||||
narrowestSampleFormat = int16Sample,
|
|
||||||
widestSampleFormat = floatSample,
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Provide the number of bytes a specific sample will take
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
#define SAMPLE_SIZE(SampleFormat) (SampleFormat >> 16)
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Generic pointer to sample data
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
typedef char *samplePtr;
|
|
||||||
typedef const char *constSamplePtr;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// The type for plugin IDs
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
typedef wxString PluginID;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Supported channel assignments
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
// Use to mark end of list
|
|
||||||
ChannelNameEOL = -1,
|
|
||||||
// The default channel assignment
|
|
||||||
ChannelNameMono,
|
|
||||||
// From this point, the channels follow the 22.2 surround sound format
|
|
||||||
ChannelNameFrontLeft,
|
|
||||||
ChannelNameFrontRight,
|
|
||||||
ChannelNameFrontCenter,
|
|
||||||
ChannelNameLowFrequency1,
|
|
||||||
ChannelNameBackLeft,
|
|
||||||
ChannelNameBackRight,
|
|
||||||
ChannelNameFrontLeftCenter,
|
|
||||||
ChannelNameFrontRightCenter,
|
|
||||||
ChannelNameBackCenter,
|
|
||||||
ChannelNameLowFrequency2,
|
|
||||||
ChannelNameSideLeft,
|
|
||||||
ChannelNameSideRight,
|
|
||||||
ChannelNameTopFrontLeft,
|
|
||||||
ChannelNameTopFrontRight,
|
|
||||||
ChannelNameTopFrontCenter,
|
|
||||||
ChannelNameTopCenter,
|
|
||||||
ChannelNameTopBackLeft,
|
|
||||||
ChannelNameTopBackRight,
|
|
||||||
ChannelNameTopSideLeft,
|
|
||||||
ChannelNameTopSideRight,
|
|
||||||
ChannelNameTopBackCenter,
|
|
||||||
ChannelNameBottomFrontCenter,
|
|
||||||
ChannelNameBottomFrontLeft,
|
|
||||||
ChannelNameBottomFrontRight,
|
|
||||||
} ChannelName, *ChannelNames;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// some frequently needed forward declarations
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class ComponentInterfaceSymbol;
|
|
||||||
|
|
||||||
using EnumValueSymbol = ComponentInterfaceSymbol;
|
|
||||||
using NumericFormatSymbol = EnumValueSymbol;
|
|
||||||
|
|
||||||
using VendorSymbol = ComponentInterfaceSymbol;
|
|
||||||
|
|
||||||
using EffectFamilySymbol = ComponentInterfaceSymbol;
|
|
||||||
|
|
||||||
#endif // __AUDACITY_TYPES_H__
|
|
||||||
|
|||||||
Reference in New Issue
Block a user