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