unit Keyman.System.DevTools.BuildMessageConstants;

interface

uses
  System.Classes,
  System.SysUtils,

  Xml.XMLIntf,
  Xml.XMLDoc;

type
  TBuildMessageConstants = class
  private
    class procedure Write(doc: IXMLDocument; const Filename: string); static;
  public
    class function Run(const LocaleXmlFilename, FileName: string): Boolean; static;
  end;

implementation

uses
  Xml.Win.msxmldom,
  Winapi.ActiveX,
  System.StrUtils;

{ TBuildMessageConstants }

class function TBuildMessageConstants.Run(const LocaleXmlFilename, FileName: string): Boolean;
var
  doc: IXMLDocument;
begin
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  try
    Xml.Win.msxmldom.MSXMLDOMDocumentFactory.AddDOMProperty('ProhibitDTD', False);

    doc := TXMLDocument.Create(nil);
    doc.ParseOptions := [poResolveExternals];  // I902 - resolve externals when loading XML files
    doc.LoadFromFile(LocaleXmlFilename);

    Write(doc, FileName);
  finally
    CoUninitialize;
  end;

  Result := True;
end;

class procedure TBuildMessageConstants.Write(doc: IXMLDocument; const Filename: string);
var
  f: TextFile;
  stype, sconst: string;
  node: IXMLNode;
  HasPreviousNode: Boolean;
begin
  AssignFile(f, FileName);
  Rewrite(f);
  writeln(f, '// Generated file - generated by devtools -buildmessageconstants at '+FormatDateTime('dd/mm/yyyy hh:nn:ss', Now));
  writeln(f, 'unit '+ChangeFileExt(ExtractFileName(FileName), '')+';'#13#10'interface'#13#10);
//  writeln(f, 'uses keymanapi_TLB;'#13#10);

  stype := 'type TMessageIdentifier = (SKNull, '#13#10;
  sconst := 'const MessageIdentifierNames: array[TMessageIdentifier] of string = (''SKNull'', '#13#10;

  node := doc.DocumentElement.ChildNodes[0];
  HasPreviousNode := False;
  while Assigned(node) do
  begin
    if node.NodeName = 'String' then
    begin
      // Legacy locale.xml format (deprecated, will be removed later)
      if HasPreviousNode then
      begin
        stype := stype + ','#13#10;
        sconst := sconst + ','#13#10;
      end;

      stype := stype + '  '+node.Attributes['Id'];
      sconst := sconst + '  '''+node.Attributes['Id']+'''';
      HasPreviousNode := True;
    end
    else if node.NodeName = 'string' then
    begin
      // Android strings.xml format
      if HasPreviousNode then
      begin
        stype := stype + ','#13#10;
        sconst := sconst + ','#13#10;
      end;

      stype := stype + '  '+node.Attributes['name'];
      sconst := sconst + '  '''+node.Attributes['name']+'''';
      HasPreviousNode := True;
    end;
    node := node.NextSibling;
  end;

  stype := stype + #13#10');';
  sconst := sconst + #13#10');';

  writeln(f, stype);
  writeln(f);
  writeln(f, 'function MsgIdFromString(const msgid: WideString): TMessageIdentifier;');
  writeln(f, 'function StringFromMsgId(const msgid: TMessageIdentifier): WideString;');
  writeln(f);
  writeln(f, 'implementation');
  writeln(f);
  writeln(f, sconst);
  writeln(f);
  writeln(f, 'function StringFromMsgId(const msgid: TMessageIdentifier): WideString;');
  writeln(f, 'begin');
  writeln(f, '  Result := MessageIdentifierNames[msgid];');
  writeln(f, 'end;');
  writeln(f);
  writeln(f, 'function MsgIdFromString(const msgid: WideString): TMessageIdentifier;');
  writeln(f, 'var i: TMessageIdentifier;');
  writeln(f, 'begin');
  writeln(f, '  for i := Low(TMessageIdentifier) to High(TMessageIdentifier) do');
  writeln(f, '    if MessageIdentifierNames[i] = msgid then begin Result := i; Exit; end;');
  writeln(f, '  Result := SKNull;');
  writeln(f, 'end;');
  writeln(f);
  writeln(f, 'end.');

  CloseFile(f);
end;

end.


