@@ -732,19 +732,24 @@ def collectOptions(elem):
732732 options = set ()
733733 messages = set ()
734734 optionsWithElems = {}
735+ attrib = {}
736+ values = set ()
735737 for group in elem .getElementsByTagName ('group' ):
736738 for option in group .getElementsByTagName ('option' ):
737739 optionId = option .getAttribute ('id' )
738740 optionType = option .getAttribute ('type' )
739741 if optionId and optionType != 'obsolete' :
740742 options .add (optionId )
741743 optionsWithElems [optionId ] = option
744+ attrib [optionId ] = sorted (option .attributes .items ())
745+ if option .getElementsByTagName ('value' ):
746+ values .add (optionId )
742747 for generator in elem .getElementsByTagName ('generator' ):
743748 for message in generator .getElementsByTagName ('message' ):
744749 messageId = message .getAttribute ('name' )
745750 messages .add (messageId )
746751
747- return (options ,optionsWithElems ,messages )
752+ return (options ,optionsWithElems ,messages , attrib , values )
748753
749754def syncWarnings (typ , existing , language ):
750755 missing = existing - language
@@ -777,7 +782,7 @@ def syncLocalizedConfig(elem, configFile, translationsDir, autoSync=False):
777782 import os
778783 import shutil
779784
780- existingOptions , existingOptionsWithElements , existingMessages = collectOptions (elem )
785+ existingOptions , existingOptionsWithElements , existingMessages , existingAttrib , existingValues = collectOptions (elem )
781786 print ("Found %d active options in %s" % (len (existingOptions ), configFile ))
782787 print ("Found %d active messages in %s" % (len (existingMessages ), configFile ))
783788
@@ -801,12 +806,104 @@ def syncLocalizedConfig(elem, configFile, translationsDir, autoSync=False):
801806 print (" Error parsing %s: %s" % (configFile , e ))
802807 continue
803808
804- langOptions , langOptionsWithElements , langMessages = collectOptions (langDoc )
809+ langOptions , langOptionsWithElements , langMessages , langAttrib , langValues = collectOptions (langDoc )
805810
806811 optionsError = syncWarnings ('Options' , existingOptions , langOptions )
807812 messagesError = syncWarnings ('Messages' , existingMessages , langMessages )
808813
809- if autoSync and (optionsError or messagesError ):
814+ # attributes handling
815+ extraOptions = langOptions - existingOptions
816+ langMatch = langOptions - extraOptions
817+ attribError = set ()
818+ for optionId in langMatch :
819+ missingAttrib = set (existingAttrib [optionId ]) - set (langAttrib [optionId ])
820+ extraAttrib = set (langAttrib [optionId ]) - set (existingAttrib [optionId ])
821+ if missingAttrib :
822+ attribError .add (optionId )
823+ print (" Missing %d %s for %s" % (len (missingAttrib ), "attributes" , optionId ))
824+
825+ if extraAttrib :
826+ attribError .add (optionId )
827+ print (" Extra %d %s for %s" % (len (extraAttrib ), "attributes" , optionId ))
828+ if not attribError :
829+ print (" OK - all %s are synchronized" % "attributes" )
830+
831+ # values handling
832+ valuesError = False
833+ # we only need options that are also in the original
834+ langValues = langValues - extraOptions
835+ # language options that should have values
836+ missingAllValues = existingValues - langValues
837+ if missingAllValues :
838+ print (" Missing %d %s: %s" % (len (missingAllValues ), "all values" , ', ' .join (sorted (list (missingAllValues ))[:5 ])))
839+ if len (missingAllValues ) > 5 :
840+ print (" ... and %d more" % (len (missingAllValues ) - 5 ))
841+ valuesError = True
842+ # language options that should have no values
843+ extraAllValues = langValues - existingValues
844+ if extraAllValues :
845+ print (" Extra %d %s: %s" % (len (extraAllValues ), "all values" , ', ' .join (sorted (list (extraAllValues ))[:5 ])))
846+ if len (extraAllValues ) > 5 :
847+ print (" ... and %d more" % (len (extraAllValues ) - 5 ))
848+ valuesError = True
849+
850+ # both have values, some furter investigations
851+ bothValues = existingValues - missingAllValues
852+ # partial extra / missing attr
853+ bothError = set ()
854+ for optionId in bothValues :
855+ optionElem = existingOptionsWithElements [optionId ]
856+ langElem = langOptionsWithElements [optionId ]
857+ optValues = set ()
858+ langValues = set ()
859+ for optValue in optionElem .getElementsByTagName ('value' ):
860+ optValues .add (optValue .getAttribute ('name' ))
861+ for langValue in langElem .getElementsByTagName ('value' ):
862+ langValues .add (langValue .getAttribute ('name' ))
863+ missingValues = optValues - langValues
864+ missingLen = len (missingValues )
865+ extraLen = len (langValues - optValues )
866+ if missingLen :
867+ print (" Missing %d %s for %s" % (missingLen , "values" , optionId ))
868+ bothError .add (optionId )
869+ if extraLen :
870+ print (" Extra %d %s for %s" % (extraLen , "values" , optionId ))
871+ bothError .add (optionId )
872+ # both have value elements
873+ bothName = optValues - missingValues
874+ for name in bothName :
875+ toCorrect = False
876+ for optValue in optionElem .getElementsByTagName ('value' ):
877+ if optValue .getAttribute ('name' ) == name :
878+ optAttr = set (optValue .attributes .items ())
879+ break
880+ for langValue in langElem .getElementsByTagName ('value' ):
881+ if langValue .getAttribute ('name' ) == name :
882+ langAttr = set (langValue .attributes .items ())
883+ break
884+ missing = optAttr - langAttr
885+ extra = langAttr - optAttr
886+ if missing or extra :
887+ if len (missing ) == 1 and len (extra ) == 1 :
888+ for attr , dummy in missing :
889+ missAttr = attr
890+ break
891+ for attr , dummy in extra :
892+ extraAttr = attr
893+ break
894+ if missAttr != 'desc' or extraAttr != 'desc' :
895+ bothError .add (optionId )
896+ toCorrect = True
897+ else :
898+ bothError .add (optionId )
899+ toCorrect = True
900+ if toCorrect :
901+ print (" Differences in attributes for %s with name %s for %s" % ("value" , name , optionId ))
902+
903+ if not (valuesError or bothError ):
904+ print (" OK - all %s are synchronized" % "values" )
905+
906+ if autoSync and (optionsError or messagesError or attribError or valuesError or bothError ):
810907 print (" Auto-syncing..." )
811908
812909 rootElement = langDoc .documentElement
@@ -838,6 +935,118 @@ def syncLocalizedConfig(elem, configFile, translationsDir, autoSync=False):
838935 parentGroupNew .appendChild (importedElem )
839936 print (" Added: %s" % optionId )
840937
938+ # handle option attributes
939+ for optionId in attribError :
940+ existingElem = existingOptionsWithElements [optionId ]
941+ langElem = langOptionsWithElements [optionId ]
942+ for attr ,val in langElem .attributes .items ():
943+ langElem .removeAttribute (attr )
944+ for attr ,val in existingElem .attributes .items ():
945+ langElem .setAttribute (attr ,val )
946+
947+ # handle values
948+ for optionId in extraAllValues :
949+ optionElem = langOptionsWithElements [optionId ]
950+ for valueElem in optionElem .getElementsByTagName ('value' ):
951+ optionElem .removeChild (valueElem )
952+ print (" Removed all values of: %s" % optionId )
953+
954+ for optionId in missingAllValues :
955+ existingElem = existingOptionsWithElements [optionId ]
956+ langElem = langOptionsWithElements [optionId ]
957+ for valueElem in existingElem .getElementsByTagName ('value' ):
958+ importedElem = langDoc .importNode (valueElem , True )
959+ langElem .appendChild (importedElem )
960+ print (" Added all values for: %s" % optionId )
961+
962+ # handle bothValue errors
963+ for optionId in bothError :
964+ optionElem = existingOptionsWithElements [optionId ]
965+ langElem = langOptionsWithElements [optionId ]
966+ optValues = set ()
967+ langValues = set ()
968+ for optValue in optionElem .getElementsByTagName ('value' ):
969+ optValues .add (optValue .getAttribute ('name' ))
970+ for langValue in langElem .getElementsByTagName ('value' ):
971+ langValues .add (langValue .getAttribute ('name' ))
972+ missing = optValues - langValues
973+ extra = langValues - optValues
974+ existingElem = existingOptionsWithElements [optionId ]
975+ langElem = langOptionsWithElements [optionId ]
976+ if missing :
977+ for miss in missing :
978+ for allVal in existingElem .getElementsByTagName ('value' ):
979+ if allVal .getAttribute ('name' ) == miss :
980+ importedElem = langDoc .importNode (allVal , True )
981+ langElem .appendChild (importedElem )
982+ print (" Added: value %s of %s" % (miss ,optionId ))
983+ if extra :
984+ for extr in extra :
985+ for allVal in langElem .getElementsByTagName ('value' ):
986+ if allVal .getAttribute ('name' ) == extr :
987+ langElem .removeChild (allVal )
988+ print (" Removed: value %s of %s" % (extr ,optionId ))
989+
990+ # both have value elements
991+ bothName = optValues - missing
992+ for name in bothName :
993+ toCorrect = False
994+ for optValue in optionElem .getElementsByTagName ('value' ):
995+ if optValue .getAttribute ('name' ) == name :
996+ optAttr = set (optValue .attributes .items ())
997+ break
998+ for langValue in langElem .getElementsByTagName ('value' ):
999+ if langValue .getAttribute ('name' ) == name :
1000+ langAttr = set (langValue .attributes .items ())
1001+ break
1002+ missing = optAttr - langAttr
1003+ extra = langAttr - optAttr
1004+ if missing or extra :
1005+ if len (missing ) == 1 and len (extra ) == 1 :
1006+ for attr , dummy in missing :
1007+ missAttr = attr
1008+ break
1009+ for attr , dummy in extra :
1010+ extraAttr = attr
1011+ break
1012+ if missAttr != 'desc' or extraAttr != 'desc' :
1013+ toCorrect = True
1014+ else :
1015+ toCorrect = True
1016+
1017+ if toCorrect :
1018+ optHasDesc = False
1019+ for optValue in optionElem .getElementsByTagName ('value' ):
1020+ if optValue .getAttribute ('name' ) == name :
1021+ for attr , dummy in optValue .attributes .items ():
1022+ if attr == 'desc' :
1023+ optHasDesc = True
1024+ break
1025+ break
1026+ langHasDesc = False
1027+ for langValue in langElem .getElementsByTagName ('value' ):
1028+ if langValue .getAttribute ('name' ) == name :
1029+ for attr , dummy in langValue .attributes .items ():
1030+ if attr == 'desc' :
1031+ langHasDesc = True
1032+ break
1033+ break
1034+ for langValue in langElem .getElementsByTagName ('value' ):
1035+ if langValue .getAttribute ('name' ) == name :
1036+ for attr , dummy in langValue .attributes .items ():
1037+ if attr != 'desc' or not optHasDesc :
1038+ langValue .removeAttribute (attr )
1039+ lang = langValue
1040+ break
1041+ for optValue in optionElem .getElementsByTagName ('value' ):
1042+ if optValue .getAttribute ('name' ) == name :
1043+ for attr , val in optValue .attributes .items ():
1044+ if attr != 'desc' or not langHasDesc :
1045+ lang .setAttribute (attr ,val )
1046+ break
1047+
1048+
1049+ # handle generator / messages
8411050 missingMessages = existingMessages - langMessages
8421051 extraMessages = langMessages - existingMessages
8431052
@@ -856,7 +1065,8 @@ def syncLocalizedConfig(elem, configFile, translationsDir, autoSync=False):
8561065 for messageId in missingMessages :
8571066 for message in parentGenerator .getElementsByTagName ('message' ):
8581067 if messageId == message .getAttribute ('name' ):
859- parentGeneratorNew .appendChild (message )
1068+ importedElem = langDoc .importNode (message , True )
1069+ parentGeneratorNew .appendChild (importedElem )
8601070 print (" Added: %s" % messageId )
8611071
8621072 backupFile = configFile + ".bak"
@@ -1110,7 +1320,7 @@ def main():
11101320 print ("#include \" configdoc.h\" " )
11111321 print ("#include \" docintf.h\" " )
11121322 print ("" )
1113- ##
1323+
11141324 print ("void addConfigDocs{0}(DocIntf *doc)" .format (locale ))
11151325 print ("{" )
11161326 for n in elem .childNodes :
0 commit comments