{ This file is part of the Free Pascal packages library. Copyright (c) 2013 by Yury Sidorov, member of the Free Pascal development team This unit is used to get format settings of the current Mac OS UI locale. Works on Mac OS X 10.3 or later. Function CFStringToStr() has been taken from CarbonProc LCL unit. See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} unit iosxlocale; {$mode objfpc}{$H+} interface uses SysUtils, MacOSAll; procedure GetMacFormatSettings(var ASettings: TFormatSettings); implementation {------------------------------------------------------------------------------ Name: CFStringToStr Params: AString - Core Foundation string ref Encoding - Result data encoding format Returns: UTF-8 string Converts Core Foundation string to string ------------------------------------------------------------------------------} function CFStringToStr(AString: CFStringRef): UTF8String; var Str: Pointer; StrSize: CFIndex; StrRange: CFRange; begin if AString=nil then begin Result:=''; Exit; end; // Try the quick way first Str:=CFStringGetCStringPtr(AString, kCFStringEncodingUTF8); if Str<>nil then Result:=PChar(Str) else begin // if that doesn't work this will StrRange.location:=0; StrRange.length:=CFStringGetLength(AString); CFStringGetBytes(AString, StrRange, kCFStringEncodingUTF8, Ord('?'), False, nil, 0, StrSize{%H-}); SetLength(Result, StrSize); if StrSize>0 then CFStringGetBytes(AString, StrRange, kCFStringEncodingUTF8, Ord('?'), False, @Result[1], StrSize, StrSize); end; end; function StrOfChar(c: AnsiChar; Count: integer): utf8string; begin SetLength(Result, Count); FillChar(PAnsiChar(Result)^, Count, c); end; function ConvertFormatStr(const fmt: utf8string): utf8string; var cnt: integer; c, q: AnsiChar; p: PAnsiChar; s: utf8string; begin Result:=''; q:=#0; cnt:=1; p:=PAnsiChar(fmt); while p^<>#0 do begin s:=''; c:=p^; if c in ['''', '"'] then begin if q=#0 then q:=c else if c=q then begin q:=#0; cnt:=1; end; s:=c; end else if q <> #0 then s:=c else begin if (p+1)^=c then Inc(cnt) else begin case c of 'y', 'Y': begin c:='y'; if cnt > 2 then cnt:=4 else cnt:=2; end; 'M', 'L': begin c:='m'; if cnt > 4 then cnt:=3; end; 'd': if cnt > 2 then cnt:=2; 'E', 'e', 'c': begin c:='d'; if (cnt < 3) or (cnt > 4) then cnt:=3; end; 'a': begin cnt:=0; s:='ampm'; end; 'h', 'H', 'k', 'K': begin c:='h'; if cnt > 2 then cnt:=2; end; 'm': begin c:='n'; if cnt>2 then cnt:=2; end; 's': if cnt>2 then cnt:=2; 'S': begin c:='z'; cnt:=1; end; 'G','u','Q','q','w','W','D','F','g','A','z','Z','v': cnt:=0; end; if cnt>0 then s:=StrOfChar(c, cnt); cnt:=1; end; end; Inc(p); if s<>'' then Result:=Result+s; end; end; procedure GetMacFormatSettings(var ASettings: TFormatSettings); var loc: CFLocaleRef; function _GetFormat(dateStyle: CFDateFormatterStyle; timeStyle: CFDateFormatterStyle; const DefFormat: utf8string): utf8string; var fmt: CFDateFormatterRef; begin Result:=''; fmt:=CFDateFormatterCreate(nil, loc, dateStyle, timeStyle); if fmt <> nil then begin Result:=ConvertFormatStr(CFStringToStr(CFDateFormatterGetFormat(fmt))); CFRelease(fmt); end; if Result = '' then Result:=DefFormat; end; function _DateToStr(fmt: CFDateFormatterRef; const AFormat: utf8string; AYear: integer; AMonth, ADay, AHour: byte; const ADefault: utf8string): utf8string; var cs: CFStringRef; gd: CFGregorianDate; at: CFAbsoluteTime; tz: CFTimeZoneRef; begin cs:=CFStringCreateWithCString(nil, Pointer(PAnsiChar(AFormat)), kCFStringEncodingUTF8); CFDateFormatterSetFormat(fmt, cs); CFRelease(cs); FillChar(gd, SIzeOf(gd), 0); gd.year:=AYear; gd.month:=AMonth; gd.day:=ADay; gd.hour:=AHour; tz:=CFTimeZoneCopyDefault; at:=CFGregorianDateGetAbsoluteTime(gd, tz); CFRelease(tz); cs:=CFDateFormatterCreateStringWithAbsoluteTime(nil, fmt, at); Result:=CFStringToStr(cs); CFRelease(cs); if Result = '' then Result:=ADefault; end; function _GetSeparator(dateStyle: CFDateFormatterStyle; timeStyle: CFDateFormatterStyle; DefSep: char): char; var fmt: CFDateFormatterRef; s: utf8string; p: PAnsiChar; begin Result:=DefSep; fmt:=CFDateFormatterCreate(nil, loc, dateStyle, timeStyle); if fmt <> nil then begin s:=_DateToStr(fmt, CFStringToStr(CFDateFormatterGetFormat(fmt)), 2000, 1, 1, 0, DefSep); s:=Trim(s); p:=PAnsiChar(s); while p^<>#0 do if (p^>' ') and (p^<'A') and not (p^ in ['0'..'9']) then begin Result:=p^; break; end else Inc(p); CFRelease(fmt); end; end; var s: utf8string; fmt: CFDateFormatterRef; i: integer; begin with ASettings do begin loc:=CFLocaleCopyCurrent; if loc=nil then exit; s:=CFStringToStr(CFLocaleGetValue(loc, kCFLocaleDecimalSeparator)); if Length(s)=1 then DecimalSeparator:=s[1]; s:=CFStringToStr(CFLocaleGetValue(loc, kCFLocaleGroupingSeparator)); if Length(s)=1 then ThousandSeparator:=s[1] else ThousandSeparator:=' '; // Unicode char has been returned. Probably it is a whitespace CurrencyString:=CFStringToStr(CFLocaleGetValue(loc, kCFLocaleCurrencySymbol)); DateSeparator:=_GetSeparator(kCFDateFormatterShortStyle, kCFDateFormatterNoStyle, DateSeparator); TimeSeparator:=_GetSeparator(kCFDateFormatterNoStyle, kCFDateFormatterShortStyle, TimeSeparator); LongDateFormat:=_GetFormat(kCFDateFormatterLongStyle, kCFDateFormatterNoStyle, LongDateFormat); ShortDateFormat:=_GetFormat(kCFDateFormatterShortStyle, kCFDateFormatterNoStyle, ShortDateFormat); LongTimeFormat:=_GetFormat(kCFDateFormatterNoStyle, kCFDateFormatterLongStyle, LongTimeFormat); ShortTimeFormat:=_GetFormat(kCFDateFormatterNoStyle, kCFDateFormatterShortStyle, ShortTimeFormat); fmt:=CFDateFormatterCreate(nil, loc, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); if fmt<>nil then begin for i:=1 to 12 do begin LongMonthNames[i]:=_DateToStr(fmt, 'LLLL', 2006, i, 1, 0, LongMonthNames[i]); ShortMonthNames[i]:=_DateToStr(fmt, 'LLL', 2006, i, 1, 0, ShortMonthNames[i]); end; for i:=1 to 7 do begin LongDayNames[i]:=_DateToStr(fmt, 'cccc', 2006, 1, i, 0, LongDayNames[i]); ShortDayNames[i]:=_DateToStr(fmt, 'ccc', 2006, 1, i, 0, ShortDayNames[i]); end; TimeAMString:=_DateToStr(fmt, 'a', 2006, 1, 1, 1, TimeAMString); TimePMString:=_DateToStr(fmt, 'a', 2006, 1, 1, 13, TimePMString); CFRelease(fmt); end; CFRelease(loc); end; end; initialization GetMacFormatSettings(DefaultFormatSettings); end.