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