In Delphi1, using FloatToStrF or CurrToStrF will automatically use the DecimalSeparator character to represent a decimal mark. Unfortunately DecimalSeparator is declared in SysUtils as Char1,2:
var 
  DecimalSeparator: Char;
While the LOCALE_SDECIMAL is allowed to be up to three characters:
Character(s) used for the decimal separator, for example, "." in "3.14" or "," in "3,14". The maximum number of characters allowed for this string is four, including a terminating null character.
This causes Delphi to fail to read the decimal separator correctly; falling back to assume a default decimal separator of ".":
DecimalSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');
On my computer, which is quite a character, this cause floating point and currency values to be incorrectly localized with a U+002E (full stop) decimal mark.
i am willing to call the Windows API functions directly, which are designed to convert floating point, or currency, values into a localized string:
Except these functions take a string of picture codes, where the only characters allowed are:
- Characters "0" through "9" (U+0030..U+0039)
- One decimal point (.) if the number is a floating-point value (U+002E)
- A minus sign in the first character position if the number is a negative value (U+002D)
What would be a good way1 to convert a floating point, or currency, value to a string that obeys those rules? e.g.
- 1234567.893332
- -1234567
given that the local user's locale (i.e. my computer):
- might not use a -to indicate negative (e.g.--)
- might not use a .to indicate a decimal point (e.g.,,)
- might not use the latin alphabet 0123456789to represent digits (e.g. [removed arabic digits that crash SO javascript parser])
A horrible, horrible, hack, which i could use:
function FloatToLocaleIndependantString(const v: Extended): string;
var
   oldDecimalSeparator: Char;
begin
   oldDecimalSeparator := SysUtils.DecimalSeparator;
   SysUtils.DecimalSeparator := '.'; //Windows formatting functions assume single decimal point
   try
      Result := FloatToStrF(Value, ffFixed, 
            18, //Precision: "should be 18 or less for values of type Extended"
            9 //Scale 0..18.   Sure...9 digits before decimal mark, 9 digits after. Why not
      );
   finally
      SysUtils.DecimalSeparator := oldDecimalSeparator;
   end;
end;
Additional info on the chain of functions the VCL uses:
- FloatToStrFand- CurrToStrFcalls:- FloatToTextcalls:
 
Note
- DecimalSeparator: Char, the single character global is deprecated, and replaced with another single character decimal separator
1 in my version of Delphi
2 and in current versions of Delphi
 
     
    