Audacity  2.2.2
Internat.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Internat.cpp
6 
7  Markus Meyer
8  Dominic Mazzoni (Mac OS X code)
9 
10 *******************************************************************//*******************************************************************/
22 
23 #include <wx/log.h>
24 #include <wx/intl.h>
25 #include <wx/filename.h>
26 
27 #include <locale.h>
28 #include <math.h> // for pow()
29 
30 #include "Experimental.h"
31 #include "FileNames.h"
32 #include "widgets/ErrorDialog.h"
33 #include "Internat.h"
34 #include "../include/audacity/IdentInterface.h"
35 
36 // in order for the static member variables to exist, they must appear here
37 // (_outside_) the class definition, in order to be allocated some storage.
38 // Otherwise, you get link errors.
39 
40 wxChar Internat::mDecimalSeparator = wxT('.'); // default
41 wxArrayString Internat::exclude;
42 wxCharBuffer Internat::mFilename;
43 
44 // DA: Use tweaked translation mechanism to replace 'Audacity' by 'DarkAudacity'.
45 #ifdef EXPERIMENTAL_DA
46 // This function allows us to replace Audacity by DarkAudacity without peppering
47 // the source code with changes. We split out this step, the customisation, as
48 // it is used on its own (without translation) in the wxTS macro.
49 AUDACITY_DLL_API const wxString& GetCustomSubstitution(const wxString& str2)
50 {
51  // If contains 'DarkAudacity, already converted.
52  if( str2.Contains( "DarkAudacity" ))
53  return str2;
54  // If does not contain 'Audacity', nothing to do.
55  if( !str2.Contains( "Audacity" ))
56  return str2;
57  wxString str3 = str2;
58  str3.Replace( "Audacity", "DarkAudacity" );
59  str3.Replace( " an DarkAudacity", " a DarkAudacity" );
60  // DA also renames sync-lock(ed) as time-lock(ed).
61  str3.Replace( "Sync-Lock", "Time-Lock" );
62  str3.Replace( "Sync-&Lock", "Time-&Lock" );
63  str3.Replace( "Sync Lock", "Time Lock" );
64  return wxTranslations::GetUntranslatedString(str3);
65 }
66 #else
67 AUDACITY_DLL_API const wxString& GetCustomSubstitution(const wxString& str1)
68 {
69  return str1 ;
70 }
71 #endif
72 
73 // In any translated string, we can replace the name 'Audacity' by 'DarkAudacity'
74 // without requiring translators to see extra strings for the two versions.
75 AUDACITY_DLL_API const wxString& GetCustomTranslation(const wxString& str1)
76 {
77  const wxString& str2 = wxGetTranslation( str1 );
78  return GetCustomSubstitution( str2 );
79 }
80 
81 
83 {
84  // Save decimal point character
85  struct lconv * localeInfo = localeconv();
86  if (localeInfo)
87  mDecimalSeparator = wxString(wxSafeConvertMB2WX(localeInfo->decimal_point)).GetChar(0);
88 
89 // wxLogDebug(wxT("Decimal separator set to '%c'"), mDecimalSeparator);
90 
91  // Setup list of characters that aren't allowed in file names
92  // Hey! The default wxPATH_NATIVE does not do as it should.
93 #if defined(__WXMAC__)
94  wxPathFormat format = wxPATH_MAC;
95 #elif defined(__WXGTK__)
96  wxPathFormat format = wxPATH_UNIX;
97 #elif defined(__WXMSW__)
98  wxPathFormat format = wxPATH_WIN;
99 #endif
100 
101  // This is supposed to return characters not permitted in paths to files
102  // or to directories
103  auto forbid = wxFileName::GetForbiddenChars(format);
104 
105  for(auto cc: forbid)
106  exclude.Add(wxString{ cc });
107 
108  // The path separators may not be forbidden, so add them
109  auto separators = wxFileName::GetPathSeparators(format);
110 
111  for(auto cc: separators) {
112  if (forbid.Find(cc) == wxNOT_FOUND)
113  exclude.Add(wxString{ cc });
114  }
115 }
116 
118 {
119  return mDecimalSeparator;
120 }
121 
122 bool Internat::CompatibleToDouble(const wxString& stringToConvert, double* result)
123 {
124  // Regardless of the locale, always respect comma _and_ point
125  wxString s = stringToConvert;
126  s.Replace(wxT(","), wxString(GetDecimalSeparator()));
127  s.Replace(wxT("."), wxString(GetDecimalSeparator()));
128  return s.ToDouble(result);
129 }
130 
131 double Internat::CompatibleToDouble(const wxString& stringToConvert)
132 {
133  double result = 0;
134  Internat::CompatibleToDouble(stringToConvert, &result);
135  return result;
136 }
137 
138 wxString Internat::ToString(double numberToConvert,
139  int digitsAfterDecimalPoint /* = -1 */)
140 {
141  wxString result = ToDisplayString(
142  numberToConvert, digitsAfterDecimalPoint);
143 
144  result.Replace(wxString(GetDecimalSeparator()), wxT("."));
145 
146  return result;
147 }
148 
149 wxString Internat::ToDisplayString(double numberToConvert,
150  int digitsAfterDecimalPoint /* = -1 */)
151 {
152  wxString decSep = wxString(GetDecimalSeparator());
153  wxString result;
154 
155  if (digitsAfterDecimalPoint == -1)
156  {
157  result.Printf(wxT("%f"), numberToConvert);
158 
159  // Not all libcs respect the decimal separator, so always convert
160  // any dots found to the decimal separator.
161  result.Replace(wxT("."), decSep);
162 
163  if (result.Find(decSep) != -1)
164  {
165  // Strip trailing zeros, but leave one, and decimal separator.
166  int pos = result.Length() - 1;
167  while ((pos > 1) &&
168  (result.GetChar(pos) == wxT('0')) &&
169  (result.GetChar(pos - 1) != decSep))
170  pos--;
171  // (Previous code removed all of them and decimal separator.)
172  // if (result.GetChar(pos) == decSep)
173  // pos--; // strip point before empty fractional part
174  result = result.Left(pos+1);
175  }
176  }
177  else
178  {
179  wxString format;
180  format.Printf(wxT("%%.%if"), digitsAfterDecimalPoint);
181  result.Printf(format, numberToConvert);
182 
183  // Not all libcs respect the decimal separator, so always convert
184  // any dots found to the decimal separator
185  result.Replace(wxT("."), decSep);
186  }
187 
188  return result;
189 }
190 
191 wxString Internat::FormatSize(wxLongLong size)
192 {
193  /* wxLongLong contains no built-in conversion to double */
194  double dSize = size.GetHi() * pow(2.0, 32); // 2 ^ 32
195  dSize += size.GetLo();
196 
197  return FormatSize(dSize);
198 }
199 
200 wxString Internat::FormatSize(double size)
201 {
202  wxString sizeStr;
203 
204  if (size == -1)
205  sizeStr = _("Unable to determine");
206  else {
207  /* make it look nice, by formatting into k, MB, etc */
208  if (size < 1024.0)
209  sizeStr = ToDisplayString(size) + wxT(" ") + _("bytes");
210  else if (size < 1024.0 * 1024.0) {
211  /* i18n-hint: Abbreviation for Kilo bytes */
212  sizeStr = ToDisplayString(size / 1024.0, 1) + wxT(" ") + _("KB");
213  }
214  else if (size < 1024.0 * 1024.0 * 1024.0) {
215  /* i18n-hint: Abbreviation for Mega bytes */
216  sizeStr = ToDisplayString(size / (1024.0 * 1024.0), 1) + wxT(" ") + _("MB");
217  }
218  else {
219  /* i18n-hint: Abbreviation for Giga bytes */
220  sizeStr = ToDisplayString(size / (1024.0 * 1024.0 * 1024.0), 1) + wxT(" ") + _("GB");
221  }
222  }
223 
224  return sizeStr;
225 }
226 
227 #if defined(__WXMSW__)
228 //
229 // On Windows, wxString::mb_str() can return a NULL pointer if the
230 // conversion to multi-byte fails. So, based on direction intent,
231 // returns a pointer to an empty string or prompts for a NEW name.
232 //
233 char *Internat::VerifyFilename(const wxString &s, bool input)
234 {
235  static wxCharBuffer buf;
236  wxString name = s;
237 
238  if (input) {
239  if ((char *) (const char *)name.mb_str() == NULL) {
240  name = wxEmptyString;
241  }
242  }
243  else {
244  wxFileName ff(name);
245  wxString ext;
246  while ((char *) (const char *)name.mb_str() == NULL) {
247  AudacityMessageBox(_("The specified filename could not be converted due to Unicode character use."));
248 
249  ext = ff.GetExt();
251  _("Specify New Filename:"),
252  wxEmptyString,
253  name,
254  ext,
255  wxT("*.") + ext,
256  wxFD_SAVE | wxRESIZE_BORDER,
257  wxGetTopLevelParent(NULL));
258  }
259  }
260 
261  mFilename = name.mb_str();
262 
263  return (char *) (const char *) mFilename;
264 }
265 #endif
266 
267 bool Internat::SanitiseFilename(wxString &name, const wxString &sub)
268 {
269  bool result = false;
270  for(const auto &item : exclude)
271  {
272  if(name.Contains(item))
273  {
274  name.Replace(item, sub);
275  result = true;
276  }
277  }
278 
279 #ifdef __WXMAC__
280  // Special Mac stuff
281  // '/' is permitted in file names as seen in dialogs, even though it is
282  // the path separator. The "real" filename as seen in the terminal has ':'.
283  // Do NOT return true if this is the only subsitution.
284  name.Replace(wxT("/"), wxT(":"));
285 #endif
286 
287  return result;
288 }
289 
290 wxString Internat::StripAccelerators(const wxString &s)
291 {
292  wxString result;
293  result.Alloc(s.Length());
294  for(size_t i = 0; i < s.Length(); i++) {
295  if (s[i] == '\t')
296  break;
297  if (s[i] != '&' && s[i] != '.')
298  result += s[i];
299  }
300  return result;
301 }
302 
303 wxArrayString LocalizedStrings(
304  const IdentInterfaceSymbol strings[], size_t nStrings)
305 {
306  wxArrayString results;
307  std::transform( strings, strings + nStrings, std::back_inserter(results),
308  std::mem_fun_ref( &IdentInterfaceSymbol::Translation ) );
309  return results;
310 }
static wxString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:191
AUDACITY_DLL_API const wxString & GetCustomSubstitution(const wxString &str1)
Definition: Internat.cpp:67
static wxString StripAccelerators(const wxString &str)
Remove accelerator charactors from strings.
Definition: Internat.cpp:290
wxArrayString LocalizedStrings(const IdentInterfaceSymbol strings[], size_t nStrings)
Definition: Internat.cpp:303
static void Init()
Initialize internationalisation support. Call this once at program start.
Definition: Internat.cpp:82
static bool SanitiseFilename(wxString &name, const wxString &sub)
Protect against Unicode to multi-byte conversion failures on Windows.
Definition: Internat.cpp:267
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
const wxString & Translation() const
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
Definition: Internat.cpp:138
int format
Definition: ExportPCM.cpp:56
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:122
static wxArrayString exclude
Definition: Internat.h:153
static wxChar mDecimalSeparator
Definition: Internat.h:150
IdentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:411
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
AUDACITY_DLL_API const wxString & GetCustomTranslation(const wxString &str1)
Definition: Internat.cpp:75
const wxChar * name
Definition: Distortion.cpp:94
static wxString ToDisplayString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, uses the user's locale's decimal separator.
Definition: Internat.cpp:149
static wxCharBuffer mFilename
Definition: Internat.h:155
static wxChar GetDecimalSeparator()
Get the decimal separator for the current locale.
Definition: Internat.cpp:117