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;
}
|