7 # Builds a list of all translation keys in the list of lines.
11 comment = line.find("#")
13 index = line.find("=")
14 while ((index > 0) and (line[index-1]=="\\")):
15 index = line.find("=", index+1)
17 allKeys.append(line[0:index])
22 # Finds all keys in the first list that are not present in the second list:
23 def findMissingKeys(first, second):
31 # Appends all the given keys to the file:
32 def appendMissingKeys(filename, keys):
33 file = open(filename, "a")
38 def handleFileSet(mainFile, files, changeFiles):
40 lines = f1.readlines()
42 keys = indexFile(lines)
44 for i in range(0, len(files)):
46 lines = f2.readlines()
48 keysPresent.append(indexFile(lines))
49 missing = findMissingKeys(keys, keysPresent[i])
51 print "\n\nFile '"+files[i]+"'\n"
53 print "----> No missing keys."
55 print "----> Missing keys:"
61 if raw_input() in ['y', 'Y']:
62 appendMissingKeys(files[i], missing)
65 # See if this file has keys that are not in the main file:
66 redundant = findMissingKeys(keysPresent[i], keys)
67 if len(redundant) > 0:
68 print "----> Possible obsolete keys (not in English language file):"
73 # print "Update file?",
74 # if raw_input() in ['y', 'Y']:
75 # removeRedundantKeys(files[i], redundant)
78 def handleJavaCode(filename, lines, keyList, notTermList):
79 #Extract first string parameter from Globals.lang call. E.g., Globals.lang("Default")
80 reOnlyString = r'"((\\"|[^"])*)"[^"]*'
81 patt = re.compile(r'Globals\s*\.\s*lang\s*\(\s*' + reOnlyString)
82 #second pattern as Mr Dlib contribution indirectly uses Global.lang
83 patta = re.compile(r'LocalizationSupport.message\(' + reOnlyString)
84 pattOnlyString = re.compile(reOnlyString)
86 #Find multiline Globals lang statements. E.g.:
87 #Globals.lang("This is my string" +
89 patt2 = re.compile(r'Globals\s*\.\s*lang\s*\(([^)])*$')
91 pattPlus = re.compile(r'^\s*\+')
93 eList = list(enumerate(lines.split("\n")))
96 linenum, curline = eList[i]
98 #Remove Java single line comments
99 if curline.find("http://") < 0:
100 curline = re.sub("//.*", "", curline)
102 while (curline != ""):
103 result = patt.search(curline)
105 result = patta.search(curline)
106 result2 = patt2.search(curline)
110 if result2 and curline.find('",') < 0:
112 # but it could be a multiline string
114 curText = result.group(1)
118 searchForPlus = False
121 while i+1 < len(eList):
122 linenum2, curline2 = eList[i+1]
123 if (not searchForPlus) or pattPlus.search(curline2):
124 #from now on, we always have to search for a plus
127 #The current line has been handled here, therefore indicate to handle the next line
132 #Search for the occurence of a string
133 result = pattOnlyString.search(curline2)
135 curText = curText + result.group(1)
136 #check for several strings in this line
137 if curline2.count('\"') > 2:
139 #check for several arguments in the line
140 if curline2.find('",') > 0:
142 if curline2.endswith(")"):
145 #plus sign at the beginning found, but no string
148 #no continuation found
152 print "%s:%d: Not terminated: %s"%(filename, linenum+1, curline)
156 if result or (found != ""):
158 #not a multiline string, found via the single line matching
159 #full string in one line
160 found = result.group(1)
162 found = found.replace(" ", "_")
163 #replace characters that need to be escaped in the language file
164 found = found.replace("=", r"\=").replace(":",r"\:")
165 #replace Java-escaped " to plain "
166 found = found.replace(r'\"','"')
167 #Java-escaped \ to plain \ need not to be converted - they have to be kept
168 #e.g., "\\#" has to be contained as "\\#" in the key
169 #found = found.replace('\\\\','\\')
170 if (found != "") and (found not in keyList):
171 keyList.append(found)
172 keyFiles[found] = (filename, linenum)
173 #print "Adding ", found
175 # print "Not adding: "+found
177 #Prepare a possible second run (multiple Globals.lang on this line)
179 lastPos = result.span()[1]
180 #regular expression is greedy. It will match until Globals.lang("
181 #therefore, we have to adjust lastPos
182 lastPos = lastPos - 14
183 if len(curline) <= lastPos:
186 curline = curline[lastPos:]
188 #terminate processing of this line, continue to next line
193 # Find all Java source files in the given directory, and read the lines of each,
194 # calling handleJavaCode on the contents:
195 def handleDir(lists, dirname, fnames):
196 keyList, notTermList = lists
198 if len(file) > 6 and file[(len(file)-5):len(file)] == ".java":
199 fl = open(dirname+os.sep+file)
202 handleJavaCode(dirname + os.sep + file, lines, keyList, notTermList)
204 # Go through subdirectories and call handleDir on all diroctories:
205 def traverseFileTree(dir):
208 os.path.walk(dir, handleDir, (keyList, notTermList))
209 print "Keys found: "+str(len(keyList))
213 # Searches out all translation calls in the Java source files, and reports which
214 # are not present in the given resource file.
216 # arg: mainFile: a .properties file with the keys to sync with
217 def findNewKeysInJavaCode(mainFile, dir, update):
221 lines = f1.readlines()
223 keys = indexFile(lines)
224 keyList = traverseFileTree(dir)
226 # Open the file again, for appending:
228 f1 = open(mainFile, "a")
231 # Look for keys that are used in the code, but not present in the language file:
233 value = key.replace("\\:",":").replace("\\=", "=")
235 fileName, lineNum = keyFiles[key]
236 print "%s:%i:Missing key: %s"%(fileName, lineNum + 1, value)
238 f1.write(key+"="+value+"\n")
240 # Look for keys in the language file that are not used in the code:
242 if key not in keyList:
243 print "Possible obsolete key: "+key
249 def lookForDuplicates(file, displayKeys):
252 lines = f1.readlines()
257 comment = line.find("#")
258 index = line.find("=")
259 if (comment != 0) and (index > 0):
261 value = line[index+1:].strip()
263 mappings[key].append(value)
266 print "Duplicate: "+file+": "+key+" =",
269 mappings[key] = [value]
271 emptyVals = emptyVals + 1
273 print "Empty value: "+file+": "+key
276 dupstring = str(duplicount)+" duplicates. "
280 emptStr = str(emptyVals)+" empty values. "
283 if duplicount+emptyVals > 0:
287 print file+": "+dupstring+emptStr+okString
288 #print file+": "+str(emptyVals)+" empty values."
291 ############# Main part ###################
293 if len(sys.argv) == 1:
294 print """This program must be run from the "src" directory right below the jabref base directory.
296 Usage: syncLang.py option
297 Option can be one of the following:
299 -c: Search the language files for empty and duplicate translations. Display only
300 counts for duplicated and empty values in each language file.
302 -d: Search the language files for empty and duplicate translations.
303 For each duplicate set found, a list will be printed showing the various
304 translations for the same key. There is currently to option to remove duplicates
307 -s [-u]: Search the Java source files for language keys. All keys that are found in the source files
308 but not in "JabRef_en.properties" are listed. If the -u option is specified, these keys will
309 automatically be added to "JabRef_en.properties".
311 The program will also list "Not terminated" keys. These are keys that are concatenated over
312 more than one line, that the program is not (currently) able to resolve.
314 Finally, the program will list "Possible obsolete keys". These are keys that are present in
315 "JabRef_en.properties", but could not be found in the Java source code. Note that the
316 "Not terminated" keys will be likely to appear here, since they were not resolved.
318 -t [-u]: Compare the contents of "JabRef_en.properties" and "Menu_en.properties" against the other
319 language files. The program will list for all the other files which keys from the English
320 file are missing. Additionally, the program will list keys in the other files which are
321 not present in the English file - possible obsolete keys.
323 If the -u option is specified, all missing keys will automatically be added to the files.
324 There is currently no option to remove obsolete keys automatically.
327 elif (len(sys.argv) >= 2) and (sys.argv[1] == "-s"):
328 if (len(sys.argv) >= 3) and (sys.argv[2] == "-u"):
332 findNewKeysInJavaCode("resource/JabRef_en.properties", ".", update)
334 elif (len(sys.argv) >= 2) and (sys.argv[1] == "-t"):
335 if (len(sys.argv) >= 3) and (sys.argv[2] == "-u"):
340 filesJabRef = filter(lambda s: (s.startswith('JabRef_') and not (s.startswith('JabRef_en'))), os.listdir("resource"));
341 filesJabRef = ["resource/" + i for i in filesJabRef];
342 filesMenu = filter(lambda s: (s.startswith('Menu_') and not (s.startswith('Menu_en'))), os.listdir("resource"));
343 filesMenu = ["resource/" + i for i in filesMenu];
345 handleFileSet("resource/JabRef_en.properties", filesJabRef, changeFiles)
346 handleFileSet("resource/Menu_en.properties", filesMenu, changeFiles)
348 elif (len(sys.argv) >= 2) and ((sys.argv[1] == "-d") or (sys.argv[1] == "-c")):
349 files = filter(lambda s: (s.startswith('JabRef_') and not (s.startswith('JabRef_en'))), os.listdir("resource"));
350 files.extend(filter(lambda s: (s.startswith('Menu_') and not (s.startswith('Menu_en'))), os.listdir("resource")));
351 files = ["resource/" + i for i in files];
353 lookForDuplicates(file, sys.argv[1] == "-d")