You've already forked lazarus-ccr
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:
@ -161,12 +161,14 @@ type
|
|||||||
by the number format parser from a format string. }
|
by the number format parser from a format string. }
|
||||||
TsNumFormatParams = class(TObject)
|
TsNumFormatParams = class(TObject)
|
||||||
private
|
private
|
||||||
|
FAllowLocalizedAMPM: Boolean;
|
||||||
protected
|
protected
|
||||||
function GetNumFormat: TsNumberFormat; virtual;
|
function GetNumFormat: TsNumberFormat; virtual;
|
||||||
function GetNumFormatStr: String; virtual;
|
function GetNumFormatStr: String; virtual;
|
||||||
public
|
public
|
||||||
{@@ Array of the format sections }
|
{@@ Array of the format sections }
|
||||||
Sections: TsNumFormatSections;
|
Sections: TsNumFormatSections;
|
||||||
|
constructor Create;
|
||||||
procedure DeleteElement(ASectionIndex, AElementIndex: Integer);
|
procedure DeleteElement(ASectionIndex, AElementIndex: Integer);
|
||||||
procedure InsertElement(ASectionIndex, AElementIndex: Integer;
|
procedure InsertElement(ASectionIndex, AElementIndex: Integer;
|
||||||
AToken: TsNumFormatToken);
|
AToken: TsNumFormatToken);
|
||||||
@ -175,6 +177,7 @@ type
|
|||||||
procedure SetDecimals(AValue: Byte);
|
procedure SetDecimals(AValue: Byte);
|
||||||
procedure SetNegativeRed(AEnable: Boolean);
|
procedure SetNegativeRed(AEnable: Boolean);
|
||||||
procedure SetThousandSep(AEnable: Boolean);
|
procedure SetThousandSep(AEnable: Boolean);
|
||||||
|
property AllowLocalizedAMPM: boolean read FAllowLocalizedAMPM write FAllowLocalizedAMPM;
|
||||||
property NumFormat: TsNumberFormat read GetNumFormat;
|
property NumFormat: TsNumberFormat read GetNumFormat;
|
||||||
property NumFormatStr: String read GetNumFormatStr;
|
property NumFormatStr: String read GetNumFormatStr;
|
||||||
end;
|
end;
|
||||||
@ -315,7 +318,8 @@ function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
|||||||
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
|
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
|
||||||
AMinIntDigits: Integer = 1): String;
|
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 ApplyTextFormat(AText: String; AParams: TsNumFormatParams): String;
|
||||||
function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams;
|
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
|
Adds an AM/PM format code to a pre-built time formatting string.
|
||||||
replacing "AM" or "PM" in the final formatted number are taken from the
|
|
||||||
TimeAMString or TimePMString of the specified FormatSettings.
|
|
||||||
|
|
||||||
@param ATimeFormatString String of time formatting codes (such as 'hh:nn')
|
@param ATimeFormatString String of time formatting codes (such as 'hh:nn')
|
||||||
@param AFormatSettings FormatSettings for locale-dependent information
|
@param AFormatSettings FormatSettings for locale-dependent information
|
||||||
@ -1130,13 +1132,8 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function AddAMPM(const ATimeFormatString: String;
|
function AddAMPM(const ATimeFormatString: String;
|
||||||
const AFormatSettings: TFormatSettings): String;
|
const AFormatSettings: TFormatSettings): String;
|
||||||
var
|
|
||||||
am, pm: String;
|
|
||||||
fs: TFormatSettings absolute AFormatSettings;
|
|
||||||
begin
|
begin
|
||||||
am := IfThen(fs.TimeAMString <> '', fs.TimeAMString, 'AM');
|
Result := Format('%s AM/PM', [StripAMPM(ATimeFormatString)]);
|
||||||
pm := IfThen(fs.TimePMString <> '', fs.TimePMString, 'PM');
|
|
||||||
Result := Format('%s %s/%s', [StripAMPM(ATimeFormatString), am, pm]);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -1470,9 +1467,15 @@ end;
|
|||||||
|
|
||||||
@param ASection Parsed section of number format elements as created by the
|
@param ASection Parsed section of number format elements as created by the
|
||||||
number format parser
|
number format parser
|
||||||
|
@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
|
@return Excel-compatible format string
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
function BuildFormatStringFromSection(const ASection: TsNumFormatSection;
|
||||||
|
AllowLocalizedAMPM: Boolean = true): String;
|
||||||
var
|
var
|
||||||
element: TsNumFormatElement;
|
element: TsNumFormatElement;
|
||||||
i, n: Integer;
|
i, n: Integer;
|
||||||
@ -1542,7 +1545,12 @@ begin
|
|||||||
else Result := Result + DupeString('s', element.IntValue);
|
else Result := Result + DupeString('s', element.IntValue);
|
||||||
nftMilliseconds:
|
nftMilliseconds:
|
||||||
Result := Result + DupeString('0', element.IntValue);
|
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;
|
if element.TextValue <> '' then Result := Result + element.TextValue;
|
||||||
nftCurrSymbol:
|
nftCurrSymbol:
|
||||||
if element.TextValue <> '' then
|
if element.TextValue <> '' then
|
||||||
@ -2189,6 +2197,12 @@ end;
|
|||||||
{ TsNumFormatParams }
|
{ TsNumFormatParams }
|
||||||
{==============================================================================}
|
{==============================================================================}
|
||||||
|
|
||||||
|
constructor TsNumFormatParams.Create;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
FAllowLocalizedAMPM := true;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Deletes a parsed number format element from the specified format section.
|
Deletes a parsed number format element from the specified format section.
|
||||||
|
|
||||||
@ -2249,7 +2263,7 @@ begin
|
|||||||
if Length(Sections) > 0 then begin
|
if Length(Sections) > 0 then begin
|
||||||
Result := BuildFormatStringFromSection(Sections[0]);
|
Result := BuildFormatStringFromSection(Sections[0]);
|
||||||
for i := 1 to High(Sections) do
|
for i := 1 to High(Sections) do
|
||||||
Result := Result + ';' + BuildFormatStringFromSection(Sections[i]);
|
Result := Result + ';' + BuildFormatStringFromSection(Sections[i], FAllowLocalizedAMPM);
|
||||||
end else
|
end else
|
||||||
Result := '';
|
Result := '';
|
||||||
end;
|
end;
|
||||||
|
@ -152,8 +152,6 @@ type
|
|||||||
|
|
||||||
procedure AddBuiltinNumFormats; virtual;
|
procedure AddBuiltinNumFormats; virtual;
|
||||||
function FindNumFormatInList(ANumFormatStr: String): Integer;
|
function FindNumFormatInList(ANumFormatStr: String): Integer;
|
||||||
// function FixColor(AColor: TsColor): TsColor; virtual;
|
|
||||||
procedure FixFormat(ACell: PCell); virtual;
|
|
||||||
procedure GetSheetDimensions(AWorksheet: TsBasicWorksheet;
|
procedure GetSheetDimensions(AWorksheet: TsBasicWorksheet;
|
||||||
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
|
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
|
||||||
procedure ListAllNumFormats; virtual;
|
procedure ListAllNumFormats; virtual;
|
||||||
@ -624,21 +622,6 @@ begin
|
|||||||
Result := -1;
|
Result := -1;
|
||||||
end;
|
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.
|
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
|
Is called when the writer needs the size for output. Column and row count
|
||||||
|
@ -418,6 +418,11 @@ type
|
|||||||
function GetLocalLinks(AWorksheet: TsBasicWorksheet): TsBiffExternSheetList;
|
function GetLocalLinks(AWorksheet: TsBasicWorksheet): TsBiffExternSheetList;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TsExcelNumFormatParser = class(TsNumFormatParser)
|
||||||
|
protected
|
||||||
|
function BuildFormatString: String; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsSpreadBIFFReader }
|
{ TsSpreadBIFFReader }
|
||||||
TsSpreadBIFFReader = class(TsCustomSpreadReader)
|
TsSpreadBIFFReader = class(TsCustomSpreadReader)
|
||||||
@ -1062,6 +1067,20 @@ begin
|
|||||||
end;
|
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 }
|
{ TsBIFFDefinedName }
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
@ -4357,7 +4376,7 @@ begin
|
|||||||
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
|
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
|
||||||
begin
|
begin
|
||||||
fmtStr := NumFormatList[i];
|
fmtStr := NumFormatList[i];
|
||||||
parser := TsNumFormatParser.Create(fmtStr, Workbook.FormatSettings);
|
parser := TsExcelNumFormatParser.Create(fmtStr, Workbook.FormatSettings);
|
||||||
try
|
try
|
||||||
fmtStr := parser.FormatString;
|
fmtStr := parser.FormatString;
|
||||||
WriteFORMAT(AStream, fmtStr, i);
|
WriteFORMAT(AStream, fmtStr, i);
|
||||||
|
@ -1823,6 +1823,7 @@ begin
|
|||||||
if (uffNumberFormat in fmt^.UsedFormattingFields) then
|
if (uffNumberFormat in fmt^.UsedFormattingFields) then
|
||||||
begin
|
begin
|
||||||
nfp := book.GetNumberFormat(fmt^.NumberFormatIndex);
|
nfp := book.GetNumberFormat(fmt^.NumberFormatIndex);
|
||||||
|
nfp.AllowLocalizedAMPM := false; // Replace "AMPM" by "AM/PM"
|
||||||
AppendToStream(AStream, Format(INDENT3 +
|
AppendToStream(AStream, Format(INDENT3 +
|
||||||
'<NumberFormat ss:Format="%s"/>' + LF, [UTF8TextToXMLText(nfp.NumFormatStr)]));
|
'<NumberFormat ss:Format="%s"/>' + LF, [UTF8TextToXMLText(nfp.NumFormatStr)]));
|
||||||
end;
|
end;
|
||||||
|
@ -3363,7 +3363,7 @@ begin
|
|||||||
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
|
for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do
|
||||||
begin
|
begin
|
||||||
numFmtStr := NumFormatList[i];
|
numFmtStr := NumFormatList[i];
|
||||||
parser := TsNumFormatParser.Create(numFmtStr, Workbook.FormatSettings);
|
parser := TsExcelNumFormatParser.Create(numFmtStr, Workbook.FormatSettings);
|
||||||
try
|
try
|
||||||
numFmtStr := UTF8TextToXMLText(parser.FormatString);
|
numFmtStr := UTF8TextToXMLText(parser.FormatString);
|
||||||
xmlStr := xmlStr + Format('<numFmt numFmtId="%d" formatCode="%s" />',
|
xmlStr := xmlStr + Format('<numFmt numFmtId="%d" formatCode="%s" />',
|
||||||
|
Reference in New Issue
Block a user