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.