""" Portfolio translation file builder ***** INSTRUCTIONS ***** 1. Make sure you have Python 2.X (tested with 2.4) installed in your system. 2. Make sure you have php available in your PATH. type "php -v" on a command line. If it returns PHP's version number then it is good. To run this script type: python portfolio_translations_picker.py NB! Separator for translation preline in case of multiple elgg_echo() call on one line is: || (see example below) NB! .php files should be using a certain system for the script to be working properly EXAMPLE: line with code /*translation:Add new resource||Delete current resource*/ code . elgg_echo('portfolio:menuitem_new_resource') . code . elgg_echo('portfolio:menuitem_delete_current_resource') . code line with code """ __author__ = "Pjotr Savitski" __version__ = "3"#XXX This is still quite unreliable beta, do not use this for real translation file creation __date__ = "14.05.2009" # Imports import os, sys import subprocess import re import shutil # Defines main_path = os.path.realpath(os.path.join(os.getcwd(), os.pardir, os.pardir)) lang_files_path = os.path.realpath(os.path.join(os.getcwd(), os.pardir, 'languages')) translations = ['en', 'et'] projects = ("dictum", "portfolio", "task_manager", "cv", "competencies", "development_blog", "development_files") # Structure: {"translation_id": [["/mod/koolielu/index.php", 20, "koolielu:featured:resource", "Featured resource"]]} all_translations = {} # Structure: [['/mod/koolielu/index.php', 20]] all_errors = [] inconsistent = [] sameval = open("errors.log", "wb") def _checkPHPAvailable(): try: command = ['php', '-version'] p = subprocess.Popen(command, stdout=subprocess.PIPE) except OSError: print "PHP is not available. Will not run!" sys.exit() def checkSameValues(): header_sent = False def send_header(): print >> sameval, "Here is a list of same default values under different keys" print >> sameval, "="*60 seen_msgids = [] for key in all_translations.keys(): msgid = all_translations[key][0][2] msgstr = all_translations[key][0][3] for k2 in all_translations.keys(): msgid2 = all_translations[k2][0][2] if msgid in seen_msgids or msgid2 in seen_msgids: continue if msgid2 == msgid: continue msgstr2 = all_translations[k2][0][3] if msgstr == msgstr2: if not header_sent: send_header() header_sent = True print >> sameval, msgid, msgid2, msgstr for fnam in all_translations[key]: print >> sameval, " ",fnam[0] print >> sameval for fnam in all_translations[k2]: print >> sameval, " ",fnam[0] print >> sameval seen_msgids.append(msgid) seen_msgids.append(msgid2) return header_sent def createTranslationFile(language): # exec php2py src = os.path.join(lang_files_path, language+'.php') if os.path.exists(src): shutil.copyfile(src, os.path.join(os.getcwd(), language+'.php')) shutil.move(src, os.path.join(lang_files_path, language+'_backup.php')) # previous version of translation gets converted to python command = ['php', 'php2py.php', language] p = subprocess.Popen(command, stdout=subprocess.PIPE) p.wait() # import language+'.py' extt = __import__(language) # read file existing = getattr(extt, language+'_translation') # delete language+'.py' sys.modules.pop(language) os.remove(language + ".py") if os.path.exists(language + ".pyc"): os.remove(language + ".pyc") # Delete file first if it already exists if os.path.exists(language + ".php"): os.remove(language + ".php") # Create new file f = open(language + ".php", "wb"); file_beginning = """""" % (language, language) # Begin file f.write(file_beginning) kept = 0 for key in all_translations.keys(): msgid = all_translations[key][0][2] msgstr = all_translations[key][0][3] exis = existing.get(msgid, None) not_translated = "" if exis: exis = exis.replace('"', '\\"') if msgstr != exis: msgstr = exis kept += 1 else: not_translated = "\n _missing_translation_" del existing[msgid] else: not_translated = "\n _missing_translation_" used_in_files = "" used_in_lines = "Lines:" if len(all_translations[key]) == 1: used_in_files = "File: %s" % (all_translations[key][0][0]) used_in_lines+= " %s" % (all_translations[key][0][1]) elif len(all_translations[key]) > 1: for occurance in all_translations[key]: used_in_files+= "\n File: %s" % (occurance[0]) if used_in_lines == "Lines:": used_in_lines+= " %s" % (occurance[1]) else: used_in_lines+= ", %s" % (occurance[1]) # Remove trhe first newline used_in_files = used_in_files[9:] trans_add = """ /* %s %s Text: %s%s */ "%s" => "%s", """ % (used_in_files, used_in_lines, all_translations[key][0][3], not_translated, msgid, msgstr) f.write(trans_add) # End file f.write(file_end) f.close() shutil.move(language+'.php', src) # TODO: Do something nice here. # this is the set of translations that weren't found from system so they will not be included in translation file print "Kept", kept, "translations for lang:", language for e in existing: print e, existing[e] def buildTranslationsArray(): """ Builds up translations array """ print "module".ljust(20), print "translations".ljust(20), print "n of files".ljust(20), print "avg per file".ljust(20), print "empty files".ljust(20) print "="*100 for x in projects: sub_path = os.path.join(main_path, x) matches = 0 nfiles = 0 emptif = 0 for root, dirs, files in os.walk(sub_path): for name in files: if name.endswith(".php") and name not in ("en.php", "et.php"): nfiles += 1 m = readFileByLine(os.path.join(root, name)) if not m: emptif += 1 matches += m if ".svn" in dirs: dirs.remove(".svn") if "languages" in dirs: dirs.remove("languages") #print "from module:", x, "matches:", matches, "files:", nfiles, "average", matches/nfiles print x.ljust(20), str(matches).ljust(20), print str(nfiles).ljust(20), str(matches/nfiles).ljust(20), print str(emptif).ljust(20) def readFileByLine(f_path): i = 1 matches = 0 prev_line = "" # Read file line by line for line in open(f_path, "r").readlines(): # Search for all occurances of suitable objects #if f_path.endswith('dummy.php'): es_search = re.findall("elgg_echo\((.*?)\)", line) #else: # es_search = re.findall("elgg_echo\((.koolielu:.*?)\)", line) if (len(es_search) > 0) and ("/*translation:" in prev_line): # See if we have case with multiple elgg_echo on one line for num in range(0, len(es_search)): matches += 1 t = es_search[num] res_id = parseTranslationId(t) res_path = parseFilePath(f_path) # This is a list res_text = parsePreTranslationLine(prev_line) if res_id not in all_translations.keys(): # Structure ["/mod/koolielu/index.php", 20, "koolielu:featured:resource", "Featured resource"] all_translations[res_id] = [[res_path, i, res_id, res_text[num]]] else: existing_value = all_translations[res_id] for ext in existing_value: if ext[3] != res_text[num]: inconsistent.append("Same key but different default value!:'"+ext[3]+"' vs '"+res_text[num]+"'") existing_value.append([res_path, i, res_id, res_text[num]]) elif (len(es_search) > 0) and ("/*translation:" not in prev_line): all_errors.append([f_path, i]) prev_line = line i+= 1 return matches def parsePreTranslationLine(text): # Example: /*translation:Add new resource||Delete resource*/ # Strip spaces value = re.search('\/\*(.*?):(.*?)\*\/', text).group(2) value = value.strip() return value.split('||') def parseTranslationId(text): # Example: "koolielu:add:new:rasource" # Getting rid of beginning and end of the string text = text[1:-1] return text def parseFilePath(src): for plugin in projects: if plugin in src: tmp_list = src.split(plugin, 1) return "/" + plugin + tmp_list[1] def displayErrors(): print >> sameval, "Translations on these lines belong to koolielu translation system, but could not be added to the resulting translation file." print >> sameval, "Please check these lines. Most probably it is due to translation preline is missing." print >> sameval, "In case of any questions, please read instructions at the beginnign of this file." for err in all_errors: print >> sameval, "File: %s Line %s" % (err[0], err[1]) if __name__ == "__main__": _checkPHPAvailable() print "Building translations. Please wait." buildTranslationsArray() has_errors = checkSameValues() for lang in translations: createTranslationFile(lang) if len(all_errors) > 0: displayErrors() has_errors = True if len(inconsistent) > 0: has_errors = True print >> sameval, "\nValues with a same key but with a different default value" print >> sameval, "="*60 def out(m): print >> sameval, m [ out(x) for x in inconsistent ] sameval.close() print "Total number of translation string:", len(all_translations.keys()) if has_errors: print print print "Please consult with errors.log" print print print "Finished."