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/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
36wxChar Internat::mDecimalSeparator = wxT('.'); // default
37// exclude is used by SanitiseFilename.
38wxArrayString 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.
45STRINGS_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
63STRINGS_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.
71STRINGS_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
134bool 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
144double Internat::CompatibleToDouble(const wxString& stringToConvert)
145{
146 double result = 0;
147 Internat::CompatibleToDouble(stringToConvert, &result);
148 return result;
149}
150
151wxString 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
162wxString 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
240bool 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}
wxT("CloseDown"))
const TranslatableString name
Definition: Distortion.cpp:82
int format
Definition: ExportPCM.cpp:56
STRINGS_API const wxString & GetCustomTranslation(const wxString &str1)
Definition: Internat.cpp:71
STRINGS_API const wxString & GetCustomSubstitution(const wxString &str1)
Definition: Internat.cpp:63
#define XO(s)
Definition: Internat.h:31
static wxChar GetDecimalSeparator()
Get the decimal separator for the current locale.
Definition: Internat.cpp:129
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
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
static wxChar mDecimalSeparator
Definition: Internat.h:153
static TranslatableString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:204
static void Init()
Initialize internationalisation support. Call this once at program start.
Definition: Internat.cpp:78
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
static void SetCeeNumberFormat()
Definition: Internat.cpp:122
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:134
static wxArrayString exclude
Definition: Internat.h:155
Holds a msgid for the translation catalog; may also bind format arguments.