unit Application.Locale;
interface
type
{$REGION 'Locale'}
/// <summary> Handles the current system locale settings </summary>
/// <remarks> This is an "ambient-context" (see more at Dependency Injection in .NET by Mark Seemann)
/// The actual work is delegated to a ILocaleSettings interface that can be overriden using the
/// Locale.Current static property. A default implementation is used if the property is not set </remarks>
Locale = record
public type
{$REGION 'ILocaleSettings'}
/// <summary> Handles the current system locale settings </summary>
ILocaleSettings = interface
['{226AF252-8EB9-47D5-9D3A-EFC8692EDF38}']
function GetCurrencyDecimalSeparator: System.Char;
/// <summary> Returns wether the given Char is valid to be used in the string representation of
/// Integer numbers </summary>
/// <param name="AllowNegative"> Allows a '-' character to be treated as valid </param>
/// <param name="AllowSpace"> Allows a ' ' character to be treated as valid </param>
function IsIntegerChar(
const Char: System.Char;
const AllowNegative: Boolean = True;
const AllowSpace: Boolean = True): Boolean;
/// <summary> Returns True if the given Char is used as the Decimal Separator for either Currency
/// or floating-point numbers (Single, Double, Extended) in their string representation </summary>
function IsDecimalSeparator(const Char: System.Char): Boolean;
/// <summary> Returns wether the given Char is valid to be used in the string representation of
/// Currency or floating-point numbers (Single, Double, Extended) </summary>
function IsCurrencyChar(const Char: System.Char; const AllowNegative: Boolean = True): Boolean;
/// <summary> Returns the Character that is used as decimal separator in the string
/// representation of Currency Values </summary>
property CurrencyDecimalSeparator: System.Char read GetCurrencyDecimalSeparator;
end;
{$ENDREGION}
strict private type
{$REGION 'Locale.TDefaultLocale'}
TDefaultLocale = class(TInterfacedObject, ILocaleSettings)
strict private const
DecimalSeparators = [',', '.'];
Digits = ['0' .. '9'];
Others = [#8];
Negative = '-';
Space = ' ';
AllowedDigitsChars = Digits;
AllowedCurrencyChars = DecimalSeparators + AllowedDigitsChars + Others;
strict private
{$REGION 'ILocaleSettings'}
function IsIntegerChar(const Char: System.Char; const AllowNegative, AllowSpace: Boolean): Boolean;
function IsCurrencyChar(const Char: System.Char; const AllowNegative: Boolean): Boolean;
function GetCurrencyDecimalSeparator: System.Char;
function IsDecimalSeparator(const Char: System.Char): Boolean;
{$ENDREGION}
end;
{$ENDREGION}
strict private
class var FCurrent: Locale.ILocaleSettings;
class function CreateDefault: Locale.ILocaleSettings; static;
class function GetCurrent: Locale.ILocaleSettings; static;
class function GetCurrencyDecimalSeparator: System.Char; static;
class procedure SetCurrent(const Value: Locale.ILocaleSettings); static;
public
/// <summary> Returns wether the given Char is valid to be used in the string representation of
/// Integer numbers </summary>
/// <param name="AllowNegative"> Allows a '-' character to be treated as valid </param>
/// <param name="AllowSpace"> Allows a ' ' character to be treated as valid </param>
class function IsIntegerChar(
const Char: System.Char;
const AllowNegative: Boolean = True;
const AllowSpace: Boolean = True): Boolean; static;
/// <summary> Returns wether the given Char is valid to be used in the string representation of
/// Currency or floating-point numbers (Single, Double, Extended) </summary>
class function IsCurrencyChar(const Char: System.Char; const AllowNegative: Boolean = True): Boolean; static;
/// <summary> Returns True if the given Char is used as the Decimal Separator for either Currency
/// or floating-point numbers (Single, Double, Extended) in their string representation </summary>
class function IsDecimalSeparator(const Char: System.Char): Boolean; static;
/// <summary> Returns the Character that is used as decimal separator in the string representation
/// of Currency Values </summary>
class property CurrencyDecimalSeparator: System.Char read GetCurrencyDecimalSeparator;
/// <summary> The System's Current implementation of the Locale Settings </summary>
class property Current: Locale.ILocaleSettings read GetCurrent write SetCurrent;
end;
{$ENDREGION}
implementation
uses
System.Guard,
System.SysUtils;
{$REGION 'Locale'}
class function Locale.CreateDefault: Locale.ILocaleSettings;
begin
Result := Locale.TDefaultLocale.Create;
end;
class function Locale.GetCurrencyDecimalSeparator: System.Char;
begin
Result := Locale.Current.CurrencyDecimalSeparator;
end;
class function Locale.GetCurrent: Locale.ILocaleSettings;
begin
if not System.Assigned(Locale.FCurrent) then
Locale.FCurrent := Locale.CreateDefault;
Result := Locale.FCurrent;
end;
class function Locale.IsIntegerChar(const Char: System.Char; const AllowNegative, AllowSpace: Boolean): Boolean;
begin
Result := Locale.Current.IsIntegerChar(Char, AllowNegative, AllowSpace);
end;
class function Locale.IsCurrencyChar(const Char: System.Char; const AllowNegative: Boolean): Boolean;
begin
Result := Locale.Current.IsCurrencyChar(Char, AllowNegative);
end;
class function Locale.IsDecimalSeparator(const Char: System.Char): Boolean;
begin
Result := Locale.Current.IsDecimalSeparator(Char);
end;
class procedure Locale.SetCurrent(const Value: Locale.ILocaleSettings);
begin
Locale.FCurrent := Guard.CheckNotNull(Value);
end;
{$REGION 'Locale.TDefaultLocale'}
function Locale.TDefaultLocale.GetCurrencyDecimalSeparator: System.Char;
begin
Result := '.';
end;
function Locale.TDefaultLocale.IsIntegerChar(
const Char: System.Char;
const AllowNegative, AllowSpace: Boolean): Boolean;
var
CharSet: TSysCharSet;
begin
CharSet := AllowedDigitsChars;
if AllowNegative then
System.Include(CharSet, Negative);
if AllowSpace then
System.Include(CharSet, Space);
Result := System.SysUtils.CharInSet(Char, CharSet);
end;
function Locale.TDefaultLocale.IsCurrencyChar(const Char: System.Char; const AllowNegative: Boolean): Boolean;
var
CharSet: TSysCharSet;
begin
CharSet := AllowedCurrencyChars;
if AllowNegative then
System.Include(CharSet, Negative);
Result := System.SysUtils.CharInSet(Char, CharSet);
end;
function Locale.TDefaultLocale.IsDecimalSeparator(const Char: System.Char): Boolean;
begin
Result := System.SysUtils.CharInSet(Char, DecimalSeparators);
end;
{$ENDREGION}
{$ENDREGION}
end.