You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
5.0 KiB

  1. /**********************************************************************
  2. Audacity: A Digital Audio Editor
  3. @file TranslatableString.cpp
  4. Paul Licameli split from Internat.cpp
  5. **********************************************************************/
  6. #include "TranslatableString.h"
  7. #include "Identifier.h"
  8. #include <wx/translation.h>
  9. const wxChar *const TranslatableString::NullContextName = wxT("*");
  10. Identifier TranslatableString::MSGID() const
  11. {
  12. return Identifier{ mMsgid };
  13. }
  14. const TranslatableString::Formatter
  15. TranslatableString::NullContextFormatter {
  16. [](const wxString & str, TranslatableString::Request request) -> wxString {
  17. switch ( request ) {
  18. case Request::Context:
  19. return NullContextName;
  20. case Request::Format:
  21. case Request::DebugFormat:
  22. default:
  23. return str;
  24. }
  25. }
  26. };
  27. bool TranslatableString::IsVerbatim() const
  28. {
  29. return DoGetContext( mFormatter ) == NullContextName;
  30. }
  31. TranslatableString &TranslatableString::Strip( unsigned codes ) &
  32. {
  33. auto prevFormatter = mFormatter;
  34. mFormatter = [prevFormatter, codes]
  35. ( const wxString & str, TranslatableString::Request request ) -> wxString {
  36. switch ( request ) {
  37. case Request::Context:
  38. return TranslatableString::DoGetContext( prevFormatter );
  39. case Request::Format:
  40. case Request::DebugFormat:
  41. default: {
  42. bool debug = request == Request::DebugFormat;
  43. auto result =
  44. TranslatableString::DoSubstitute(
  45. prevFormatter,
  46. str, TranslatableString::DoGetContext( prevFormatter ),
  47. debug );
  48. if ( codes & MenuCodes ) {
  49. // Don't use this, it's in wxCore
  50. // result = wxStripMenuCodes( result );
  51. decltype( result ) temp;
  52. temp.swap(result);
  53. for ( auto iter = temp.begin(), end = temp.end();
  54. iter != end; ++iter ) {
  55. // Stop at trailing hot key name
  56. if ( *iter == '\t' )
  57. break;
  58. // Strip & (unless escaped by another preceding &)
  59. if ( *iter == '&' && ++iter == end )
  60. break;
  61. result.append( 1, *iter );
  62. }
  63. }
  64. if ( codes & Ellipses ) {
  65. if (result.EndsWith(wxT("...")))
  66. result = result.Left( result.length() - 3 );
  67. // Also check for the single-character Unicode ellipsis
  68. else if (result.EndsWith(wxT("\u2026")))
  69. result = result.Left( result.length() - 1 );
  70. }
  71. return result;
  72. }
  73. }
  74. };
  75. return *this;
  76. }
  77. wxString TranslatableString::DoGetContext( const Formatter &formatter )
  78. {
  79. return formatter ? formatter( {}, Request::Context ) : wxString{};
  80. }
  81. wxString TranslatableString::DoSubstitute( const Formatter &formatter,
  82. const wxString &format, const wxString &context, bool debug )
  83. {
  84. return formatter
  85. ? formatter( format, debug ? Request::DebugFormat : Request::Format )
  86. : // come here for most translatable strings, which have no formatting
  87. ( debug ? format : wxGetTranslation(
  88. format
  89. #if HAS_I18N_CONTEXTS
  90. , wxString{}, context
  91. #endif
  92. ) );
  93. }
  94. wxString TranslatableString::DoChooseFormat(
  95. const Formatter &formatter,
  96. const wxString &singular, const wxString &plural, unsigned nn, bool debug )
  97. {
  98. // come here for translatable strings that choose among forms by number;
  99. // if not debugging, then two keys are passed to an overload of
  100. // wxGetTranslation, and also a number.
  101. // Some languages might choose among more or fewer than two forms
  102. // (e.g. Arabic has duals and Russian has complicated declension rules)
  103. wxString context;
  104. return ( debug || NullContextName == (context = DoGetContext(formatter)) )
  105. ? ( nn == 1 ? singular : plural )
  106. : wxGetTranslation(
  107. singular, plural, nn
  108. #if HAS_I18N_CONTEXTS
  109. , wxString{} // domain
  110. , context
  111. #endif
  112. );
  113. }
  114. TranslatableString &TranslatableString::Join(
  115. const TranslatableString arg, const wxString &separator ) &
  116. {
  117. auto prevFormatter = mFormatter;
  118. mFormatter =
  119. [prevFormatter,
  120. arg /* = std::move( arg ) */,
  121. separator](const wxString &str, Request request)
  122. -> wxString {
  123. switch ( request ) {
  124. case Request::Context:
  125. return TranslatableString::DoGetContext( prevFormatter );
  126. case Request::Format:
  127. case Request::DebugFormat:
  128. default: {
  129. bool debug = request == Request::DebugFormat;
  130. return
  131. TranslatableString::DoSubstitute( prevFormatter,
  132. str, TranslatableString::DoGetContext( prevFormatter ),
  133. debug )
  134. + separator
  135. + arg.DoFormat( debug );
  136. }
  137. }
  138. };
  139. return *this;
  140. }
  141. const TranslatableString TranslatableString::Inaudible{ wxT("\a") };