File: Internat.cpp

package info (click to toggle)
audacity 3.7.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 134,800 kB
  • sloc: cpp: 366,277; ansic: 198,323; lisp: 7,761; sh: 3,414; python: 1,501; xml: 1,385; perl: 854; makefile: 125
file content (236 lines) | stat: -rw-r--r-- 6,880 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/**********************************************************************

  Audacity: A Digital Audio Editor

  Internat.cpp

  Markus Meyer
  Dominic Mazzoni (Mac OS X code)

*******************************************************************//*!

\class Internat
\brief Internationalisation support.

This class is used to help internationalisation and in general
compatibility with different locales and character sets.
It deals mostly with converting numbers, but also has important
functions to convert to/from UTF-8, which is used in XML files
and on Mac OS X for the filesystem.

*//*******************************************************************/

#include "Internat.h"

#include <wx/log.h>
#include <wx/filename.h>

#include <locale.h>
#include <math.h> // for pow()

// in order for the static member variables to exist, they must appear here
// (_outside_) the class definition, in order to be allocated some storage.
// Otherwise, you get link errors.

wxChar Internat::mDecimalSeparator = wxT('.'); // default
// exclude is used by SanitiseFilename.
wxArrayString Internat::exclude;

STRINGS_API const wxString& GetCustomSubstitution(const wxString& str1)
{
   return str1 ;
}

// In any translated string, we can replace the name 'Audacity' with fork names
// without requiring translators to see extra strings for the two versions.
STRINGS_API const wxString& GetCustomTranslation(const wxString& str1)
{
   const wxString& str2 = wxGetTranslation( str1 );
   return GetCustomSubstitution( str2 );
}


void Internat::Init()
{
   // Save decimal point character
   struct lconv * localeInfo = localeconv();
   if (localeInfo)
      mDecimalSeparator = wxString(wxSafeConvertMB2WX(localeInfo->decimal_point)).GetChar(0);

//   wxLogDebug(wxT("Decimal separator set to '%c'"), mDecimalSeparator);

   // Setup list of characters that aren't allowed in file names
   // Hey!  The default wxPATH_NATIVE does not do as it should.
#if defined(__WXMAC__)
   wxPathFormat format = wxPATH_MAC;
#elif defined(__WXGTK__)
   wxPathFormat format = wxPATH_UNIX;
#elif defined(__WXMSW__)
   wxPathFormat format = wxPATH_WIN;
#endif

   // This is supposed to return characters not permitted in paths to files
   // or to directories
   auto forbid = wxFileName::GetForbiddenChars(format);

   for (auto cc: forbid) {
#if defined(__WXGTK__)
      if (cc == wxT('*') || cc == wxT('?')) {
         continue;
      }
#endif
      exclude.push_back(wxString{ cc });
   }

   // The path separators may not be forbidden, so add them
   //auto separators = wxFileName::GetPathSeparators(format);

   // Bug 1441 exclude all separators from filenames on all platforms.
   auto separators = wxString("\\/");

   for(auto cc: separators) {
      if (forbid.Find(cc) == wxNOT_FOUND)
         exclude.push_back(wxString{ cc });
   }
}

void Internat::SetCeeNumberFormat()
{
   wxSetlocale( LC_NUMERIC, "C" );
   mDecimalSeparator = '.';
}


wxChar Internat::GetDecimalSeparator()
{
   return mDecimalSeparator;
}

bool Internat::CompatibleToDouble(const wxString& stringToConvert, double* result)
{
   // Regardless of the locale, always respect comma _and_ point
   wxString s = stringToConvert;
   // Convert to C locale decimal point for stable parsing.
   s.Replace(wxT(","), wxT("."));
   s.Replace(wxString(GetDecimalSeparator()), wxT("."));
   return s.ToCDouble(result);
}

double Internat::CompatibleToDouble(const wxString& stringToConvert)
{
   double result = 0;
   Internat::CompatibleToDouble(stringToConvert, &result);
   return result;
}

wxString Internat::ToString(double numberToConvert,
                     int digitsAfterDecimalPoint /* = -1 */)
{
   wxString result = ToDisplayString(
      numberToConvert, digitsAfterDecimalPoint);

   result.Replace(wxString(GetDecimalSeparator()), wxT("."));

   return result;
}

wxString Internat::ToDisplayString(double numberToConvert,
                                    int digitsAfterDecimalPoint /* = -1 */)
{
   wxString decSep = wxString(GetDecimalSeparator());
   wxString result;

   if (digitsAfterDecimalPoint == -1)
   {
      result.Printf(wxT("%f"), numberToConvert);

      // Not all libcs respect the decimal separator, so always convert
      // any dots found to the decimal separator.
      result.Replace(wxT("."), decSep);

      if (result.Find(decSep) != -1)
      {
         // Strip trailing zeros, but leave one, and decimal separator.
         int pos = result.length() - 1;
         while ((pos > 1) &&
                  (result.GetChar(pos) == wxT('0')) &&
                  (result.GetChar(pos - 1) != decSep))
            pos--;
         // (Previous code removed all of them and decimal separator.)
         //    if (result.GetChar(pos) == decSep)
         //       pos--; // strip point before empty fractional part
         result = result.Left(pos+1);
      }
   }
   else
   {
      wxString format;
      format.Printf(wxT("%%.%if"), digitsAfterDecimalPoint);
      result.Printf(format, numberToConvert);

      // Not all libcs respect the decimal separator, so always convert
      // any dots found to the decimal separator
      result.Replace(wxT("."), decSep);
   }

   return result;
}

TranslatableString Internat::FormatSize(wxLongLong size)
{
   /* wxLongLong contains no built-in conversion to double */
   double dSize = size.GetHi() * pow(2.0, 32);  // 2 ^ 32
   dSize += size.GetLo();

   return FormatSize(dSize);
}

TranslatableString Internat::FormatSize(double size)
{
   TranslatableString sizeStr;

   if (size == -1)
      sizeStr = XO("Unable to determine");
   else {
      /* make it look nice, by formatting into k, MB, etc */
      if (size < 1024.0)
         sizeStr = XO("%s bytes").Format( ToDisplayString(size) );
      else if (size < 1024.0 * 1024.0) {
         /* i18n-hint: Abbreviation for Kilo bytes */
         sizeStr = XO("%s KB").Format( ToDisplayString(size / 1024.0, 1) );
      }
      else if (size < 1024.0 * 1024.0 * 1024.0) {
         /* i18n-hint: Abbreviation for Mega bytes */
         sizeStr = XO("%s MB").Format( ToDisplayString(size / (1024.0 * 1024.0), 1) );
      }
      else {
         /* i18n-hint: Abbreviation for Giga bytes */
         sizeStr = XO("%s GB").Format( ToDisplayString(size / (1024.0 * 1024.0 * 1024.0), 1) );
      }
   }

   return sizeStr;
}

bool Internat::SanitiseFilename(wxString &name, const wxString &sub)
{
   bool result = false;
   for(const auto &item : exclude)
   {
      if(name.Contains(item))
      {
         name.Replace(item, sub);
         result = true;
      }
   }

#ifdef __WXMAC__
   // Special Mac stuff
   // '/' is permitted in file names as seen in dialogs, even though it is
   // the path separator.  The "real" filename as seen in the terminal has ':'.
   // Do NOT return true if this is the only substitution.
   name.Replace(wxT("/"), wxT(":"));
#endif

   return result;
}