Audacity  3.0.3
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 "Internat.h"
24 
25 #include <wx/log.h>
26 #include <wx/intl.h>
27 #include <wx/filename.h>
28 
29 #include <locale.h>
30 #include <math.h> // for pow()
31 
32 // in order for the static member variables to exist, they must appear here
33 // (_outside_) the class definition, in order to be allocated some storage.
34 // Otherwise, you get link errors.
35 
36 wxChar Internat::mDecimalSeparator = wxT('.'); // default
37 // exclude is used by SanitiseFilename.
38 wxArrayString Internat::exclude;
39 
40 // DA: Use tweaked translation mechanism to replace 'Audacity' by 'DarkAudacity'.
41 #ifdef EXPERIMENTAL_DA
42 // This function allows us to replace Audacity by DarkAudacity without peppering
43 // the source code with changes. We split out this step, the customisation, as
44 // it is used on its own (without translation) in the wxTS macro.
45 STRINGS_API const wxString& GetCustomSubstitution(const wxString& str2)
46 {
47  // If contains 'DarkAudacity, already converted.
48  if( str2.Contains( "DarkAudacity" ))
49  return str2;
50  // If does not contain 'Audacity', nothing to do.
51  if( !str2.Contains( "Audacity" ))
52  return str2;
53  wxString str3 = str2;
54  str3.Replace( "Audacity", "DarkAudacity" );
55  str3.Replace( " an DarkAudacity", " a DarkAudacity" );
56  // DA also renames sync-lock(ed) as time-lock(ed).
57  str3.Replace( "Sync-Lock", "Time-Lock" );
58  str3.Replace( "Sync-&Lock", "Time-&Lock" );
59  str3.Replace( "Sync Lock", "Time Lock" );
60  return wxTranslations::GetUntranslatedString(str3);
61 }
62 #else
63 STRINGS_API const wxString& GetCustomSubstitution(const wxString& str1)
64 {
65  return str1 ;
66 }
67 #endif
68 
69 // In any translated string, we can replace the name 'Audacity' by 'DarkAudacity'
70 // without requiring translators to see extra strings for the two versions.
71 STRINGS_API const wxString& GetCustomTranslation(const wxString& str1)
72 {
73  const wxString& str2 = wxGetTranslation( str1 );
74  return GetCustomSubstitution( str2 );
75 }
76 
77 
79 {
80  // Save decimal point character
81  struct lconv * localeInfo = localeconv();
82  if (localeInfo)
83  mDecimalSeparator = wxString(wxSafeConvertMB2WX(localeInfo->decimal_point)).GetChar(0);
84 
85 // wxLogDebug(wxT("Decimal separator set to '%c'"), mDecimalSeparator);
86 
87  // Setup list of characters that aren't allowed in file names
88  // Hey! The default wxPATH_NATIVE does not do as it should.
89 #if defined(__WXMAC__)
90  wxPathFormat format = wxPATH_MAC;
91 #elif defined(__WXGTK__)
92  wxPathFormat format = wxPATH_UNIX;
93 #elif defined(__WXMSW__)
94  wxPathFormat format = wxPATH_WIN;
95 #endif
96 
97  // This is supposed to return characters not permitted in paths to files
98  // or to directories
99  auto forbid = wxFileName::GetForbiddenChars(format);
100 
101  for (auto cc: forbid) {
102 #if defined(__WXGTK__)
103  if (cc == wxT('*') || cc == wxT('?')) {
104  continue;
105  }
106 #endif
107  exclude.push_back(wxString{ cc });
108  }
109 
110  // The path separators may not be forbidden, so add them
111  //auto separators = wxFileName::GetPathSeparators(format);
112 
113  // Bug 1441 exclude all separators from filenames on all platforms.
114  auto separators = wxString("\\/");
115 
116  for(auto cc: separators) {
117  if (forbid.Find(cc) == wxNOT_FOUND)
118  exclude.push_back(wxString{ cc });
119  }
120 }
121 
123 {
124  wxSetlocale( LC_NUMERIC, "C" );
125  mDecimalSeparator = '.';
126 }
127 
128 
130 {
131  return mDecimalSeparator;
132 }
133 
134 bool Internat::CompatibleToDouble(const wxString& stringToConvert, double* result)
135 {
136  // Regardless of the locale, always respect comma _and_ point
137  wxString s = stringToConvert;
138  // Convert to C locale decimal point for stable parsing.
139  s.Replace(wxT(","), wxT("."));
140  s.Replace(wxString(GetDecimalSeparator()), wxT("."));
141  return s.ToCDouble(result);
142 }
143 
144 double Internat::CompatibleToDouble(const wxString& stringToConvert)
145 {
146  double result = 0;
147  Internat::CompatibleToDouble(stringToConvert, &result);
148  return result;
149 }
150 
151 wxString Internat::ToString(double numberToConvert,
152  int digitsAfterDecimalPoint /* = -1 */)
153 {
154  wxString result = ToDisplayString(
155  numberToConvert, digitsAfterDecimalPoint);
156 
157  result.Replace(wxString(GetDecimalSeparator()), wxT("."));
158 
159  return result;
160 }
161 
162 wxString Internat::ToDisplayString(double numberToConvert,
163  int digitsAfterDecimalPoint /* = -1 */)
164 {
165  wxString decSep = wxString(GetDecimalSeparator());
166  wxString result;
167 
168  if (digitsAfterDecimalPoint == -1)
169  {
170  result.Printf(wxT("%f"), numberToConvert);
171 
172  // Not all libcs respect the decimal separator, so always convert
173  // any dots found to the decimal separator.
174  result.Replace(wxT("."), decSep);
175 
176  if (result.Find(decSep) != -1)
177  {
178  // Strip trailing zeros, but leave one, and decimal separator.
179  int pos = result.length() - 1;
180  while ((pos > 1) &&
181  (result.GetChar(pos) == wxT('0')) &&
182  (result.GetChar(pos - 1) != decSep))
183  pos--;
184  // (Previous code removed all of them and decimal separator.)
185  // if (result.GetChar(pos) == decSep)
186  // pos--; // strip point before empty fractional part
187  result = result.Left(pos+1);
188  }
189  }
190  else
191  {
192  wxString format;
193  format.Printf(wxT("%%.%if"), digitsAfterDecimalPoint);
194  result.Printf(format, numberToConvert);
195 
196  // Not all libcs respect the decimal separator, so always convert
197  // any dots found to the decimal separator
198  result.Replace(wxT("."), decSep);
199  }
200 
201  return result;
202 }
203 
205 {
206  /* wxLongLong contains no built-in conversion to double */
207  double dSize = size.GetHi() * pow(2.0, 32); // 2 ^ 32
208  dSize += size.GetLo();
209 
210  return FormatSize(dSize);
211 }
212 
214 {
215  TranslatableString sizeStr;
216 
217  if (size == -1)
218  sizeStr = XO("Unable to determine");
219  else {
220  /* make it look nice, by formatting into k, MB, etc */
221  if (size < 1024.0)
222  sizeStr = XO("%s bytes").Format( ToDisplayString(size) );
223  else if (size < 1024.0 * 1024.0) {
224  /* i18n-hint: Abbreviation for Kilo bytes */
225  sizeStr = XO("%s KB").Format( ToDisplayString(size / 1024.0, 1) );
226  }
227  else if (size < 1024.0 * 1024.0 * 1024.0) {
228  /* i18n-hint: Abbreviation for Mega bytes */
229  sizeStr = XO("%s MB").Format( ToDisplayString(size / (1024.0 * 1024.0), 1) );
230  }
231  else {
232  /* i18n-hint: Abbreviation for Giga bytes */
233  sizeStr = XO("%s GB").Format( ToDisplayString(size / (1024.0 * 1024.0 * 1024.0), 1) );
234  }
235  }
236 
237  return sizeStr;
238 }
239 
240 bool Internat::SanitiseFilename(wxString &name, const wxString &sub)
241 {
242  bool result = false;
243  for(const auto &item : exclude)
244  {
245  if(name.Contains(item))
246  {
247  name.Replace(item, sub);
248  result = true;
249  }
250  }
251 
252 #ifdef __WXMAC__
253  // Special Mac stuff
254  // '/' is permitted in file names as seen in dialogs, even though it is
255  // the path separator. The "real" filename as seen in the terminal has ':'.
256  // Do NOT return true if this is the only substitution.
257  name.Replace(wxT("/"), wxT(":"));
258 #endif
259 
260  return result;
261 }
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
GetCustomSubstitution
STRINGS_API const wxString & GetCustomSubstitution(const wxString &str1)
Definition: Internat.cpp:63
Internat::GetDecimalSeparator
static wxChar GetDecimalSeparator()
Get the decimal separator for the current locale.
Definition: Internat.cpp:129
XO
#define XO(s)
Definition: Internat.h:31
GetCustomTranslation
STRINGS_API const wxString & GetCustomTranslation(const wxString &str1)
Definition: Internat.cpp:71
Internat::FormatSize
static TranslatableString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:204
name
const TranslatableString name
Definition: Distortion.cpp:98
format
int format
Definition: ExportPCM.cpp:56
Internat.h
Internat::SetCeeNumberFormat
static void SetCeeNumberFormat()
Definition: Internat.cpp:122
Internat::mDecimalSeparator
static wxChar mDecimalSeparator
Definition: Internat.h:153
Internat::ToDisplayString
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:162
Internat::ToString
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
Definition: Internat.cpp:151
Internat::SanitiseFilename
static bool SanitiseFilename(wxString &name, const wxString &sub)
Check a proposed file name string for illegal characters and remove them return true iff name is "vis...
Definition: Internat.cpp:240
Internat::exclude
static wxArrayString exclude
Definition: Internat.h:155
Internat::CompatibleToDouble
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:134
Internat::Init
static void Init()
Initialize internationalisation support. Call this once at program start.
Definition: Internat.cpp:78