fpspreadsheet: Fix localized AM/PM string appearing in time format strings (https://forum.lazarus.freepascal.org/index.php/topic,46069.msg327309.html#msg327309).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7043 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2019-07-16 22:11:00 +00:00
parent b472802603
commit 347c7328d1
5 changed files with 50 additions and 33 deletions

View File

@ -161,12 +161,14 @@ type
by the number format parser from a format string. }
TsNumFormatParams = class(TObject)
private
FAllowLocalizedAMPM: Boolean;
protected
function GetNumFormat: TsNumberFormat; virtual;
function GetNumFormatStr: String; virtual;
public
{@@ Array of the format sections }
Sections: TsNumFormatSections;
constructor Create;
procedure DeleteElement(ASectionIndex, AElementIndex: Integer);
procedure InsertElement(ASectionIndex, AElementIndex: Integer;
AToken: TsNumFormatToken);
@ -175,6 +177,7 @@ type
procedure SetDecimals(AValue: Byte);
procedure SetNegativeRed(AEnable: Boolean);
procedure SetThousandSep(AEnable: Boolean);
property AllowLocalizedAMPM: boolean read FAllowLocalizedAMPM write FAllowLocalizedAMPM;
property NumFormat: TsNumberFormat read GetNumFormat;
property NumFormatStr: String read GetNumFormatStr;
end;
@ -315,7 +318,8 @@ function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
AMinIntDigits: Integer = 1): String;
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
function BuildFormatStringFromSection(const ASection: TsNumFormatSection;
AllowLocalizedAMPM: Boolean = true): String;
function ApplyTextFormat(AText: String; AParams: TsNumFormatParams): String;
function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams;
@ -1118,9 +1122,7 @@ end;
{==============================================================================}
{@@ ----------------------------------------------------------------------------
Adds an AM/PM format code to a pre-built time formatting string. The strings
replacing "AM" or "PM" in the final formatted number are taken from the
TimeAMString or TimePMString of the specified FormatSettings.
Adds an AM/PM format code to a pre-built time formatting string.
@param ATimeFormatString String of time formatting codes (such as 'hh:nn')
@param AFormatSettings FormatSettings for locale-dependent information
@ -1130,13 +1132,8 @@ end;
-------------------------------------------------------------------------------}
function AddAMPM(const ATimeFormatString: String;
const AFormatSettings: TFormatSettings): String;
var
am, pm: String;
fs: TFormatSettings absolute AFormatSettings;
begin
am := IfThen(fs.TimeAMString <> '', fs.TimeAMString, 'AM');
pm := IfThen(fs.TimePMString <> '', fs.TimePMString, 'PM');
Result := Format('%s %s/%s', [StripAMPM(ATimeFormatString), am, pm]);
Result := Format('%s AM/PM', [StripAMPM(ATimeFormatString)]);
end;
{@@ ----------------------------------------------------------------------------
@ -1470,9 +1467,15 @@ end;
@param ASection Parsed section of number format elements as created by the
number format parser
@return Excel-compatible format string
@param AllowLocalizedAMPM Replaces "AMPM" in a time format string by "AM/PM".
"AMPM" is allowed by FPS, but not by Excel. When converting a time to
string it is replaced by the localized strings
FormatSettings.TimeAMString/.TimePMString.
@return Excel-compatible format string
-------------------------------------------------------------------------------}
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
function BuildFormatStringFromSection(const ASection: TsNumFormatSection;
AllowLocalizedAMPM: Boolean = true): String;
var
element: TsNumFormatElement;
i, n: Integer;
@ -1542,7 +1545,12 @@ begin
else Result := Result + DupeString('s', element.IntValue);
nftMilliseconds:
Result := Result + DupeString('0', element.IntValue);
nftSign, nftSignBracket, nftExpChar, nftExpSign, nftAMPM, nftDateTimeSep:
nftAMPM:
if Lowercase(element.TextValue) = 'ampm' then
Result := Result + 'AM/PM'
else if element.TextValue <> '' then
Result := Result + element.TextValue;
nftSign, nftSignBracket, nftExpChar, nftExpSign, nftDateTimeSep:
if element.TextValue <> '' then Result := Result + element.TextValue;
nftCurrSymbol:
if element.TextValue <> '' then
@ -2189,6 +2197,12 @@ end;
{ TsNumFormatParams }
{==============================================================================}
constructor TsNumFormatParams.Create;
begin
inherited;
FAllowLocalizedAMPM := true;
end;
{@@ ----------------------------------------------------------------------------
Deletes a parsed number format element from the specified format section.
@ -2249,7 +2263,7 @@ begin
if Length(Sections) > 0 then begin
Result := BuildFormatStringFromSection(Sections[0]);
for i := 1 to High(Sections) do
Result := Result + ';' + BuildFormatStringFromSection(Sections[i]);
Result := Result + ';' + BuildFormatStringFromSection(Sections[i], FAllowLocalizedAMPM);
end else
Result := '';
end;

View File

@ -152,8 +152,6 @@ type
procedure AddBuiltinNumFormats; virtual;
function FindNumFormatInList(ANumFormatStr: String): Integer;
// function FixColor(AColor: TsColor): TsColor; virtual;
procedure FixFormat(ACell: PCell); virtual;
procedure GetSheetDimensions(AWorksheet: TsBasicWorksheet;
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
procedure ListAllNumFormats; virtual;
@ -624,21 +622,6 @@ begin
Result := -1;
end;
{@@ ----------------------------------------------------------------------------
If formatting features of a cell are not supported by the destination file
format of the writer, here is the place to apply replacements.
Must be overridden by descendants, nothin happens here. See BIFF2.
@param ACell Pointer to the cell being investigated. Note that this cell
does not belong to the workbook, but is a cell of the
FFormattingStyles array.
-------------------------------------------------------------------------------}
procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
begin
Unused(ACell);
// to be overridden
end;
{@@ ----------------------------------------------------------------------------
Determines the size of the worksheet to be written. VirtualMode is respected.
Is called when the writer needs the size for output. Column and row count

View File

@ -418,6 +418,11 @@ type
function GetLocalLinks(AWorksheet: TsBasicWorksheet): TsBiffExternSheetList;
end;
TsExcelNumFormatParser = class(TsNumFormatParser)
protected
function BuildFormatString: String; override;
end;
{ TsSpreadBIFFReader }
TsSpreadBIFFReader = class(TsCustomSpreadReader)
@ -1062,6 +1067,20 @@ begin
end;
{ FPS can use an "ampm" modifier in the time format string, Excel cannot.
The function replaces is by "AM/PM". }
function TsExcelNumFormatParser.BuildFormatString: String;
var
p: Integer;
begin
Result := inherited;
if IsTimeFormat or IsDateTimeFormat then begin
p := pos('ampm', Lowercase(Result));
if p > 0 then Result := Copy(Result, 1, p-1) + 'AM/PM';
end;
end;
{------------------------------------------------------------------------------}
{ TsBIFFDefinedName }
{------------------------------------------------------------------------------}
@ -4357,7 +4376,7 @@ begin
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
begin
fmtStr := NumFormatList[i];
parser := TsNumFormatParser.Create(fmtStr, Workbook.FormatSettings);
parser := TsExcelNumFormatParser.Create(fmtStr, Workbook.FormatSettings);
try
fmtStr := parser.FormatString;
WriteFORMAT(AStream, fmtStr, i);

View File

@ -1823,6 +1823,7 @@ begin
if (uffNumberFormat in fmt^.UsedFormattingFields) then
begin
nfp := book.GetNumberFormat(fmt^.NumberFormatIndex);
nfp.AllowLocalizedAMPM := false; // Replace "AMPM" by "AM/PM"
AppendToStream(AStream, Format(INDENT3 +
'<NumberFormat ss:Format="%s"/>' + LF, [UTF8TextToXMLText(nfp.NumFormatStr)]));
end;

View File

@ -3363,7 +3363,7 @@ begin
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
begin
numFmtStr := NumFormatList[i];
parser := TsNumFormatParser.Create(numFmtStr, Workbook.FormatSettings);
parser := TsExcelNumFormatParser.Create(numFmtStr, Workbook.FormatSettings);
try
numFmtStr := UTF8TextToXMLText(parser.FormatString);
xmlStr := xmlStr + Format('<numFmt numFmtId="%d" formatCode="%s" />',