spiegel-keyman/common/windows/delphi/tools/devtools/Keyman.System.DevTools.BuildSetupStringTranslations.pas
2022-06-10 07:26:21 +10:00

198 lines
5.6 KiB
ObjectPascal

unit Keyman.System.DevTools.BuildSetupStringTranslations;
interface
uses
System.Classes,
System.SysUtils,
Xml.XMLIntf,
Xml.XMLDoc;
type
TBuildSetupStringTranslations = class
private
class function ProcessFile(const SourceFile, DestinationFile, BCP47, BCP47ID: string): Boolean; static;
class function PascalifyString(s: string): string; static;
public
class function Run(SourcePath, DestinationPath: string): Boolean; static;
end;
implementation
uses
Xml.Win.msxmldom,
Winapi.ActiveX,
System.Generics.Collections,
System.StrUtils,
System.TypInfo,
System.Variants,
Keyman.System.AndroidStringToKeymanLocaleString,
SetupStrings; // From Desktop/Setup
{ TBuildSetupStringTranslations }
class function TBuildSetupStringTranslations.PascalifyString(s: string): string;
var
i: Integer;
ch: Integer;
InQuotes: Boolean;
begin
InQuotes := False;
Result := '';
for i := 1 to Length(s) do
begin
ch := Ord(s[i]);
if (ch < 32) or (ch > 126) or (ch = Ord('''')) then
begin
if InQuotes then
Result := Result + '''';
InQuotes := False;
// Coming from UTF-8 XML, we may have only #10 so convert to #13#10 if so
if (ch = 10) and (i > 1) and (Ord(s[i-1]) <> 13)
then Result := Result + '#13#10'
else Result := Result + '#'+IntToStr(ch);
end
else
begin
if not InQuotes then
Result := Result + '''';
InQuotes := True;
Result := Result + Char(ch);
end;
// If string is too long, Delphi doesn't like it
if (i mod 64) = 0 then
if InQuotes
then Result := Result + '''+'''
else Result := Result + '+';
end;
if InQuotes then
Result := Result + '''';
end;
class function TBuildSetupStringTranslations.ProcessFile(const SourceFile,
DestinationFile, BCP47, BCP47ID: string): Boolean;
var
n: Integer;
iit: TInstallInfoText;
doc: IXmlDocument;
f: TextFile;
sconst: string;
node: IXMLNode;
HasPreviousNode: Boolean;
strings: TDictionary<TInstallInfoText, string>;
begin
doc := TXMLDocument.Create(nil);
doc.ParseOptions := [poResolveExternals]; // I902 - resolve externals when loading XML files
doc.LoadFromFile(SourceFile);
strings := TDictionary<TInstallInfoText, string>.Create;
try
node := doc.DocumentElement.ChildNodes[0];
while Assigned(node) do
begin
if node.NodeName = 'string' then
begin
n := GetEnumValue(TypeInfo(TInstallInfoText), VarToStr(node.Attributes['name']));
if (n >= Ord(Low(TInstallInfoText))) and (n <= Ord(High(TInstallInfoText))) then
strings.Add(TInstallInfoText(n), PascalifyString(TAndroidStringToKeymanLocaleString.Transform(VarToStr(node.NodeValue))));
end;
node := node.NextSibling;
end;
AssignFile(f, DestinationFile);
Rewrite(f);
writeln(f, '// Generated file - generated by devtools -buildsetupstrings at '+FormatDateTime('dd/mm/yyyy hh:nn:ss', Now));
writeln(f, 'unit '+ChangeFileExt(ExtractFileName(DestinationFile), '')+';'#13#10'interface'#13#10);
writeln(f, 'uses Keyman.Setup.System.SetupUILanguageManager, SetupStrings;'#13#10);
sconst := 'const FLocaleStrings_'+BCP47ID+': TSetupUILanguageManager.TLocaleArray = ('#13#10;
HasPreviousNode := False;
for iit := Low(TInstallInfoText) to High(TInstallInfoText) do
begin
if HasPreviousNode then
sconst := sconst + ','#13#10;
if strings.ContainsKey(iit)
then sconst := sconst + ' '+strings[iit]
else sconst := sconst + ' ''''';
HasPreviousNode := True;
end;
finally
strings.Free;
end;
sconst := sconst + #13#10');';
writeln(f, sconst);
writeln(f);
writeln(f, 'implementation');
writeln(f);
writeln(f, 'initialization');
writeln(f,' TSetupUILanguageManager.RegisterSetupStrings('''+BCP47+''', FLocaleStrings_'+BCP47ID+');');
writeln(f, 'end.');
CloseFile(f);
Result := True;
end;
class function TBuildSetupStringTranslations.Run(SourcePath,
DestinationPath: string): Boolean;
var
f: TSearchRec;
outfile: TextFile;
SourceFile, DestFile, BCP47, BCP47ID: string;
HasPreviousNode: Boolean;
begin
SourcePath := IncludeTrailingPathDelimiter(SourcePath);
DestinationPath := IncludeTrailingPathDelimiter(DestinationPath);
// Iterate through SourcePath/*/strings.xml and generate DestinationPath/Keyman.Setup.System.Locale.*.pas file for each
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
try
Xml.Win.msxmldom.MSXMLDOMDocumentFactory.AddDOMProperty('ProhibitDTD', False);
AssignFile(outfile, DestinationPath+'Keyman.Setup.System.Locales.pas');
Rewrite(outfile);
writeln(outfile, 'unit Keyman.Setup.System.Locales;');
writeln(outfile, 'interface');
writeln(outfile, 'implementation');
writeln(outfile, 'uses');
HasPreviousNode := False;
if FindFirst(SourcePath+'*', faDirectory, f) = 0 then
begin
repeat
BCP47 := f.Name;
BCP47ID := ReplaceText(BCP47, '-', '_');
SourceFile := SourcePath+BCP47+'\strings.xml';
DestFile := DestinationPath+'Keyman.Setup.System.Locale.'+BCP47ID+'.pas';
if (BCP47 <> '..') and (BCP47 <> '.') and FileExists(SourcePath+BCP47+'\strings.xml') then
begin
if not ProcessFile(SourceFile, DestFile, BCP47, BCP47ID) then
Exit(False);
if HasPreviousNode then
writeln(outfile, ',');
write(outfile, ' Keyman.Setup.System.Locale.'+BCP47ID);
HasPreviousNode := True;
end;
until FindNext(f) <> 0;
FindClose(f);
end;
writeln(outfile, ';');
writeln(outfile, 'end.');
CloseFile(outfile);
finally
CoUninitialize;
end;
Result := True;
end;
end.