continue LANGUAGE_DIR = os.path.join(SOURCE_DIR, "{}.lproj".format(OUTPUTLANGUAGE)) if not os.path.exists(LANGUAGE_DIR): raise ValueError('Source file not found for {}'.format(OUTPUTLANGUAGE)) IN_FILES = [ os.path.join(root, name) for root, dirs, files in os.walk(LANGUAGE_DIR) for name in files if name.endswith(".strings") ] for IN_FILE in IN_FILES: strings = strparser.parse_strings(filename=IN_FILE) for item in strings: value = item['value'] # escape the words that needs not to be translated if value in ['OK']: continue translated = translate(value, OUTPUTLANGUAGE, INPUTLANGUAGE).replace('\\ ', '\\').replace('\\ n ', '\\n').replace('\\n ', '\\n').replace('/ ', '/') inplace_change(IN_FILE, value, translated) print("Finished translating {}".format(IN_FILE)) tmp_file = "{}.bak".format(IN_FILE) if os.path.exists(tmp_file): os.remove(tmp_file)
def synchronize(target_file, lc): #add,remove, update (translate or copy from base) # parse target file target_kv = {} target_kc = {} target_error_lines = [] if not notexist_or_empty_file(target_file): parsed_strings = strparser.parse_strings(filename=target_file) for item in parsed_strings: k, e = item['key'], item['error'] # line error if e: target_error_lines.append(e) if not target_error_lines: target_kv[k] = item['value'] target_kc[k] = item['comment'] # parsing complete or return. if target_error_lines: print('(!) Syntax error - Skip') return False, None, None, target_error_lines # base base_content = base_dict[os.path.basename(target_file)] base_kv = {} base_kc = {} for item in base_content: k, e = item['key'], item['error'] # line error if e: print('(!) WARNING : Syntax error from Base -> ', k, ':', e) base_kv[k] = item['value'] base_kc[k] = item['comment'] force_adding_keys = base_kv.keys( ) if __KEYS_FORCE_TRANSLATE_ALL__ else __KEYS_FORCE_TRANSLATE__ adding_keys = list( ((set(base_kv.keys()) - set(target_kv.keys())) | (set(base_kv.keys()) & set(force_adding_keys))) \ - set(base_kv.keys() if __FOLLOWING_ALL_KEYS_IFNOT_EXIST__ else __KEYS_FOLLOW_BASE__) \ ) removing_keys = list(set(target_kv.keys()) - set(base_kv.keys())) existing_keys = list( set(base_kv.keys()) - (set(adding_keys) | set(removing_keys))) # Filter if __ONLY_FOR_KEYS__ option activated if __ONLY_FOR_KEYS__: adding_keys = list(set(adding_keys) & set(__ONLY_FOR_KEYS__)) removing_keys = list(set(removing_keys) & set(__ONLY_FOR_KEYS__)) existing_keys = list(set(existing_keys) & set(__ONLY_FOR_KEYS__)) updated_keys = [] """ perform translate """ translated_kv = {} reversed_matched_kv = {} # {"ratio":float, "ignored":True|False} reversed_translated_kv = {} if len(adding_keys): print('Translating...') translated_kv = dict( zip( adding_keys, strtrans.translate_strs([base_kv[k] for k in adding_keys], lc))) if __VERIFY_TRANS_RESULTS__: print('Reversing results and matching...') reversed_translated_kv = dict( zip( adding_keys, strtrans.translate_strs( [translated_kv[_ak] for _ak in adding_keys], 'en'))) for bk in adding_keys: if bk in reversed_translated_kv: ratio = fuzz.partial_ratio(base_kv[bk], reversed_translated_kv[bk]) should_ignore = __IGNORE_UNVERIFIED_RESULTS__ and ratio <= __RATIO_TO_IGNORE_UNVERIFIED_RESULTS__ if should_ignore: translated_kv[bk] = base_kv[ bk] # copy from base set reversed_matched_kv[bk] = { "ratio": ratio, "ignored": should_ignore } updated_content = [] for item in base_content: k = item['key'] newitem = dict.fromkeys(item.keys()) newitem['key'] = k target_value, target_comment = target_kv.get(k), target_kc.get(k) newitem['value'] = target_value or item['value'] newitem[ 'comment'] = target_comment if __IGNORE_COMMENTS__ else target_comment or base_kc[ k] needs_update_comment = False if __IGNORE_COMMENTS__ else not target_comment and base_kc[ k] # added if k in adding_keys: if k in translated_kv: newitem['value'] = translated_kv[k] if not newitem['comment']: newitem['comment'] = 'Translated from: {0}'.format( base_kv[k]) reversed_matched_msg = '' if k in reversed_matched_kv: reversed_matched_msg = Fore.CYAN + "({}% Matched{}: \'{}\' <- \'{}\' <- \'{}\')".format( reversed_matched_kv[k]["ratio"], ", So ignored [X]" if reversed_matched_kv[k]["ignored"] else "", reversed_translated_kv[k], newitem['value'], base_kv[k]) + Style.RESET_ALL print( '[Add] "{0}" = "{1}" <- {2}'.format( k, newitem['value'], base_kv[k]), reversed_matched_msg) else: newitem['value'] = target_kv[k] if not newitem['comment']: newitem[ 'comment'] = 'Translate failed from: {0}'.format( base_kv[k]) print(Fore.RED + '[Error] "{0}" = "{1}" X <- {2}'.format( k, newitem['value'], base_kv[k]) + Style.RESET_ALL) # exists elif k in existing_keys: if k != "Base" and __CUTTING_LENGTH_RATIO__ > 0: if target_value != base_kv[k] \ and len_unicode(target_value) > float(len_unicode(base_kv[k]))*__CUTTING_LENGTH_RATIO__ \ or needs_update_comment: print(Fore.YELLOW + '(!) Length of "', target_value, '" is longer than"', base_kv[k], '" as', len(target_value), '>', len(base_kv[k]), Style.RESET_ALL) newitem['value'] = base_kv[k] updated_keys.append(k) if not lc in global_result_logs: global_result_logs[lc] = {} global_result_logs[lc][k] = (target_value, base_kv[k]) else: newitem['value'] = target_value or base_kv[k] elif k in __KEYS_FOLLOW_BASE__: newitem['value'] = base_kv[k] if target_value != base_kv[k] or needs_update_comment: updated_keys.append(k) else: newitem['value'] = target_value or base_kv[k] if not target_value or needs_update_comment: updated_keys.append(k) updated_content.append(newitem) # removed or wrong for k in removing_keys: print(Fore.RED + '[Remove]', k, Style.RESET_ALL) if len(adding_keys) or len(updated_keys) or len(removing_keys): print( Fore.WHITE + '(i) Changed Keys: Added {0}, Updated {1}, Removed {2}'.format( len(adding_keys), len(updated_keys), len(removing_keys)), Style.RESET_ALL) # check verification failed items target_verified_items = None if len(reversed_matched_kv): target_verified_items = { k: { 'ratio': reversed_matched_kv[k]["ratio"], 'original': base_kv[k], 'reversed': reversed_translated_kv[k], 'translated': translated_kv[k] } for k in reversed_matched_kv.keys() } return updated_content and ( len(adding_keys) > 0 or len(updated_keys) > 0 or len(removing_keys) > 0 ), updated_content, translated_kv, target_error_lines, target_verified_items
def main(): parser = argparse.ArgumentParser( description= 'Automatically translate and synchronize .strings files from defined base language.' ) parser.add_argument( '-b', '--base-lang-name', help= 'A base(or source) localizable resource name.(default=\'Base\'), (e.g. "Base" via \'Base.lproj\', "en" via \'en.lproj\')', default='Base', required=False) parser.add_argument( '-x', '--excluding-lang-names', type=str, help= 'A localizable resource name that you want to exclude. (e.g. "Base" via \'Base.lproj\', "en" via \'en.lproj\')', default=[], required=False, nargs='+') parser.add_argument( '-f', '--force-translate-keys', type=str, help= 'Keys in the strings to update and translate by force. (input nothing for all keys.)', default=[], required=False, nargs='*') parser.add_argument('-o', '--following-base-keys', type=str, help='Keys in the strings to follow from "Base.', default=[], required=False, nargs='+') parser.add_argument( '-w', '--following-base-if-not-exists', type=str, help= 'With this option, all keys will be followed up with base values if they does not exist.', default=None, required=False, nargs='*') parser.add_argument( '-l', '--cutting-length-ratio-with-base', type=float, help='Keys in the float as the ratio to compare the length of "Base"', default=[], required=False, nargs='+') parser.add_argument('-c', '--ignore-comments', help='Allows ignoring comment synchronization.', default=None, required=False, nargs='*') parser.add_argument('-v', '--verify-results', help='Verify translated results via reversed results', default=None, required=False, nargs='*') parser.add_argument( '-s', '--include-secondary-languages', help='Include Additional Secondary Languages. (+63 language codes)', default=None, required=False, nargs='*') parser.add_argument( '-i', '--ignore-unverified-results', help='Allows ignoring unverified results when appending them.', default=None, required=False, nargs='*') parser.add_argument( 'target path', help= 'Target localization resource path. (root path of Base.lproj, default=./)', default='./', nargs='?') parser.add_argument( 'only for keys', help= 'Some specified keys for exclusive work. All operations will work for only that keys therefore other keys will be ignored. Not specified by default. (default=None)', default=None, nargs='*') args = vars(parser.parse_args()) reload(sys) sys.setdefaultencoding('utf-8') # configure arguments __LOCALE_XCODE_BASE_LOWERCASE__ = 'base' __DIR_SUFFIX__ = ".lproj" __FILE_SUFFIX__ = ".strings" __FILE_INTENT_SUFFIX__ = ".intentdefinition" __FILE_DICT_SUFFIX__ = ".stringsdict" __RESOURCE_PATH__ = expanduser(args['target path']) __ONLY_FOR_KEYS__ = args['only for keys'] __BASE_LANG__ = args['base_lang_name'] __EXCLUDING_LANGS__ = args['excluding_lang_names'] __KEYS_FORCE_TRANSLATE__ = args['force_translate_keys'] __KEYS_FORCE_TRANSLATE_ALL__ = ( '--force-translate-keys' in sys.argv or '-f' in sys.argv) and not __KEYS_FORCE_TRANSLATE__ __KEYS_FOLLOW_BASE__ = args['following_base_keys'] __CUTTING_LENGTH_RATIO__ = (args['cutting_length_ratio_with_base'] or [0])[0] __FOLLOWING_ALL_KEYS_IFNOT_EXIST__ = args[ 'following_base_if_not_exists'] is not None __IGNORE_COMMENTS__ = args['ignore_comments'] is not None __IGNORE_UNVERIFIED_RESULTS__ = args[ 'ignore_unverified_results'] is not None __RATIO_TO_IGNORE_UNVERIFIED_RESULTS__ = int( args['ignore_unverified_results'] [0]) if __IGNORE_UNVERIFIED_RESULTS__ and len( args['ignore_unverified_results']) else 0 __VERIFY_TRANS_RESULTS__ = __IGNORE_UNVERIFIED_RESULTS__ or args[ 'verify_results'] is not None __INCLUDE_SECONDARY_LANGUAGES__ = args[ 'include_secondary_languages'] is not None # Locale settings # [language designator] en, fr # [language designator]_[region designator] en_GB, zh_HK # [language designator]-[script designator] az-Arab, zh-Hans # [language designator]-[script designator]_[region designator] zh-Hans_HK print('(i) Initializing for supported languages ...') __lang_codes = strlocale.default_supporting_xcode_lang_codes() if __INCLUDE_SECONDARY_LANGUAGES__: __lang_codes += strlocale.secondary_supporting_xcode_lang_codes() __XCODE_LPROJ_SUPPORTED_LOCALES_MAP__ = strlocale.map_locale_codes( __lang_codes, strtrans.supported_locale_codes()) __XCODE_LPROJ_SUPPORTED_LOCALES__ = __XCODE_LPROJ_SUPPORTED_LOCALES_MAP__.keys( ) print(Fore.WHITE + '(i) Supported numbers of locale code :', str(len(__XCODE_LPROJ_SUPPORTED_LOCALES__)), Style.RESET_ALL) print(__XCODE_LPROJ_SUPPORTED_LOCALES__) # handle base if __BASE_LANG__.endswith(__DIR_SUFFIX__): __BASE_RESOUCE_DIR__ = __BASE_LANG__ __BASE_LANG__ = __BASE_LANG__.split(__DIR_SUFFIX__)[0] else: __BASE_RESOUCE_DIR__ = __BASE_LANG__ + __DIR_SUFFIX__ if not __BASE_LANG__.lower() == __LOCALE_XCODE_BASE_LOWERCASE__: __BASE_LANG__ = strlocale.lang(__BASE_LANG__) # setup Translator & langs # read ios langs print(Fore.WHITE + '(i) Fetching supported locale codes for ios9 ...', Style.RESET_ALL) __IOS9_CODES__ = [ lang_row[0] for lang_row in csv.reader( open(resolve_file_path('lc_ios9.tsv'), 'rb'), delimiter='\t') ] print(Fore.WHITE + '(i) Supported numbers of locale code :', len(__IOS9_CODES__), Style.RESET_ALL) global_result_logs = {} def merge_two_dicts(x, y): '''Given two dicts, merge them into a new dict as a shallow copy.''' z = x.copy() z.update(y) return z # core function def synchronize(target_file, lc): #add,remove, update (translate or copy from base) # parse target file target_kv = {} target_kc = {} target_error_lines = [] if not notexist_or_empty_file(target_file): parsed_strings = strparser.parse_strings(filename=target_file) for item in parsed_strings: k, e = item['key'], item['error'] # line error if e: target_error_lines.append(e) if not target_error_lines: target_kv[k] = item['value'] target_kc[k] = item['comment'] # parsing complete or return. if target_error_lines: print('(!) Syntax error - Skip') return False, None, None, target_error_lines # base base_content = base_dict[os.path.basename(target_file)] base_kv = {} base_kc = {} for item in base_content: k, e = item['key'], item['error'] # line error if e: print('(!) WARNING : Syntax error from Base -> ', k, ':', e) base_kv[k] = item['value'] base_kc[k] = item['comment'] force_adding_keys = base_kv.keys( ) if __KEYS_FORCE_TRANSLATE_ALL__ else __KEYS_FORCE_TRANSLATE__ adding_keys = list( ((set(base_kv.keys()) - set(target_kv.keys())) | (set(base_kv.keys()) & set(force_adding_keys))) \ - set(base_kv.keys() if __FOLLOWING_ALL_KEYS_IFNOT_EXIST__ else __KEYS_FOLLOW_BASE__) \ ) removing_keys = list(set(target_kv.keys()) - set(base_kv.keys())) existing_keys = list( set(base_kv.keys()) - (set(adding_keys) | set(removing_keys))) # Filter if __ONLY_FOR_KEYS__ option activated if __ONLY_FOR_KEYS__: adding_keys = list(set(adding_keys) & set(__ONLY_FOR_KEYS__)) removing_keys = list(set(removing_keys) & set(__ONLY_FOR_KEYS__)) existing_keys = list(set(existing_keys) & set(__ONLY_FOR_KEYS__)) updated_keys = [] """ perform translate """ translated_kv = {} reversed_matched_kv = {} # {"ratio":float, "ignored":True|False} reversed_translated_kv = {} if len(adding_keys): print('Translating...') translated_kv = dict( zip( adding_keys, strtrans.translate_strs([base_kv[k] for k in adding_keys], lc))) if __VERIFY_TRANS_RESULTS__: print('Reversing results and matching...') reversed_translated_kv = dict( zip( adding_keys, strtrans.translate_strs( [translated_kv[_ak] for _ak in adding_keys], 'en'))) for bk in adding_keys: if bk in reversed_translated_kv: ratio = fuzz.partial_ratio(base_kv[bk], reversed_translated_kv[bk]) should_ignore = __IGNORE_UNVERIFIED_RESULTS__ and ratio <= __RATIO_TO_IGNORE_UNVERIFIED_RESULTS__ if should_ignore: translated_kv[bk] = base_kv[ bk] # copy from base set reversed_matched_kv[bk] = { "ratio": ratio, "ignored": should_ignore } updated_content = [] for item in base_content: k = item['key'] newitem = dict.fromkeys(item.keys()) newitem['key'] = k target_value, target_comment = target_kv.get(k), target_kc.get(k) newitem['value'] = target_value or item['value'] newitem[ 'comment'] = target_comment if __IGNORE_COMMENTS__ else target_comment or base_kc[ k] needs_update_comment = False if __IGNORE_COMMENTS__ else not target_comment and base_kc[ k] # added if k in adding_keys: if k in translated_kv: newitem['value'] = translated_kv[k] if not newitem['comment']: newitem['comment'] = 'Translated from: {0}'.format( base_kv[k]) reversed_matched_msg = '' if k in reversed_matched_kv: reversed_matched_msg = Fore.CYAN + "({}% Matched{}: \'{}\' <- \'{}\' <- \'{}\')".format( reversed_matched_kv[k]["ratio"], ", So ignored [X]" if reversed_matched_kv[k]["ignored"] else "", reversed_translated_kv[k], newitem['value'], base_kv[k]) + Style.RESET_ALL print( '[Add] "{0}" = "{1}" <- {2}'.format( k, newitem['value'], base_kv[k]), reversed_matched_msg) else: newitem['value'] = target_kv[k] if not newitem['comment']: newitem[ 'comment'] = 'Translate failed from: {0}'.format( base_kv[k]) print(Fore.RED + '[Error] "{0}" = "{1}" X <- {2}'.format( k, newitem['value'], base_kv[k]) + Style.RESET_ALL) # exists elif k in existing_keys: if k != "Base" and __CUTTING_LENGTH_RATIO__ > 0: if target_value != base_kv[k] \ and len_unicode(target_value) > float(len_unicode(base_kv[k]))*__CUTTING_LENGTH_RATIO__ \ or needs_update_comment: print(Fore.YELLOW + '(!) Length of "', target_value, '" is longer than"', base_kv[k], '" as', len(target_value), '>', len(base_kv[k]), Style.RESET_ALL) newitem['value'] = base_kv[k] updated_keys.append(k) if not lc in global_result_logs: global_result_logs[lc] = {} global_result_logs[lc][k] = (target_value, base_kv[k]) else: newitem['value'] = target_value or base_kv[k] elif k in __KEYS_FOLLOW_BASE__: newitem['value'] = base_kv[k] if target_value != base_kv[k] or needs_update_comment: updated_keys.append(k) else: newitem['value'] = target_value or base_kv[k] if not target_value or needs_update_comment: updated_keys.append(k) updated_content.append(newitem) # removed or wrong for k in removing_keys: print(Fore.RED + '[Remove]', k, Style.RESET_ALL) if len(adding_keys) or len(updated_keys) or len(removing_keys): print( Fore.WHITE + '(i) Changed Keys: Added {0}, Updated {1}, Removed {2}'.format( len(adding_keys), len(updated_keys), len(removing_keys)), Style.RESET_ALL) # check verification failed items target_verified_items = None if len(reversed_matched_kv): target_verified_items = { k: { 'ratio': reversed_matched_kv[k]["ratio"], 'original': base_kv[k], 'reversed': reversed_translated_kv[k], 'translated': translated_kv[k] } for k in reversed_matched_kv.keys() } return updated_content and ( len(adding_keys) > 0 or len(updated_keys) > 0 or len(removing_keys) > 0 ), updated_content, translated_kv, target_error_lines, target_verified_items def write_file(target_file, parsed_list): suc = False try: f = codecs.open(target_file, "w", "utf-8") contents = '' for content in parsed_list: if content['comment']: contents += '/*{0}*/'.format(content['comment']) + '\n' contents += '"{0}" = "{1}";'.format(content['key'], content['value']) + '\n' f.write(contents) suc = True except IOError: print('IOError to open', target_file) finally: f.close() return suc def remove_file(target_file): try: os.rename(target_file, target_file + '.deleted') return True except IOError: print('IOError to rename', target_file) return False def create_file(target_file): open(target_file, 'a').close() def notexist_or_empty_file(target_file): return not os.path.exists(target_file) or os.path.getsize( target_file) == 0 def resolve_file_names(target_file_names): return map( lambda f: f.decode('utf-8'), filter( lambda f: f.endswith(__FILE_SUFFIX__) or f.endswith( __FILE_INTENT_SUFFIX__), target_file_names)) base_dict = {} results_dict = {} # Get Base Language Specs walked = list(os.walk(__RESOURCE_PATH__, topdown=True)) # Init with Base.lproj for dir, subdirs, files in walked: if os.path.basename(dir) == __BASE_RESOUCE_DIR__: for _file in resolve_file_names(files): f = os.path.join(dir, _file) if notexist_or_empty_file(f): continue parsed_objs = None # parse .strings if f.endswith(__FILE_SUFFIX__): parsed_objs = strparser.parse_strings(filename=f) # parse .intentdefinition elif f.endswith(__FILE_INTENT_SUFFIX__): print('[i] Found "{0}" in {1}. Parse ....'.format( os.path.basename(f), __BASE_RESOUCE_DIR__)) parsed_objs = strparser_intentdefinition.parse_strings(f) # replace to dest extenstion .strings _file = _file.replace(__FILE_INTENT_SUFFIX__, __FILE_SUFFIX__) # write original .strings file to local write_file(os.path.join(dir, _file), parsed_objs) if not parsed_objs: continue base_dict[_file] = parsed_objs if not base_dict: print('[!] Not found "{0}" in target path "{1}"'.format( __BASE_RESOUCE_DIR__, __RESOURCE_PATH__)) sys.exit(0) # Exist or Create supporting lproj dirs. print('Check and verifiy resources ...') current_lproj_names = [ os.path.splitext(os.path.basename(lproj_path))[0] for lproj_path in filter(lambda d: d.endswith(__DIR_SUFFIX__), [dir for dir, subdirs, files in walked]) ] notexisted_lproj_names = list( set(__XCODE_LPROJ_SUPPORTED_LOCALES__) - set(current_lproj_names)) creating_lproj_dirs = [ expanduser(os.path.join(__RESOURCE_PATH__, ln + __DIR_SUFFIX__)) for ln in notexisted_lproj_names ] if creating_lproj_dirs: print('Following lproj dirs does not exists. Creating ...') for d in creating_lproj_dirs: print('Created', d) os.mkdir(d) # Start to sync localizable files. print('Start synchronizing...') for file in base_dict: print('Target:', file) for dir, subdirs, files in walked: files = resolve_file_names(files) if dir.endswith((__DIR_SUFFIX__)): lproj_name = os.path.basename(dir).split(__DIR_SUFFIX__)[0] if lproj_name == __BASE_LANG__: continue if not lproj_name in __XCODE_LPROJ_SUPPORTED_LOCALES_MAP__: print('Does not supported: ', lproj_name) continue lc = __XCODE_LPROJ_SUPPORTED_LOCALES_MAP__[lproj_name] if strlocale.matched_locale_code(lc, __EXCLUDING_LANGS__): print('Skip: ', lc) continue results_dict[lc] = { 'deleted_files': [], 'added_files': [], 'updated_files': [], 'skipped_files': [], 'translated_files_lines': {}, 'error_lines_kv': {}, 'verified_result': {} } # if not supported_lang(lc): # print('Does not supported: ', lc) # results_dict[lc]['skipped_files'] = join_path_all(dir, files) # continue print('\n', 'Analayzing localizables... {1} (at {0})'.format(dir, lc)) added_files = list(set(base_dict.keys()) - set(files)) removed_files = list(set(files) - set(base_dict.keys())) existing_files = list( set(files) - (set(added_files) | set(removed_files))) added_files = join_path_all(dir, added_files) removed_files = join_path_all(dir, removed_files) existing_files = join_path_all(dir, existing_files) added_cnt, updated_cnt, removed_cnt = 0, 0, 0 translated_files_lines = results_dict[lc]['translated_files_lines'] error_files = results_dict[lc]['error_lines_kv'] # remove - file for removed_file in removed_files: print('Removing File... {0}'.format(removed_file)) if remove_file(removed_file): removed_cnt += 1 # add - file for added_file in added_files: print('Adding File... {0}'.format(added_file)) create_file(added_file) u, c, t, e, m = synchronize(added_file, lc) # error if e: error_files[added_file] = e # normal elif u and write_file(added_file, c): added_cnt += 1 translated_files_lines[added_file] = t # verify failed for k in (m or {}): results_dict[lc]['verified_result'][k] = m[k] # exist - lookup lines for ext_file in existing_files: u, c, t, e, m = synchronize(ext_file, lc) # error if e: error_files[ext_file] = e # normal elif u: print('Updating File... {0}'.format(ext_file)) if write_file(ext_file, c): updated_cnt = +1 translated_files_lines[ext_file] = t # verify failed for k in (m or {}): results_dict[lc]['verified_result'][k] = m[k] if added_cnt or updated_cnt or removed_cnt or error_files: print( Fore.WHITE + '(i) Changed Files : Added {0}, Updated {1}, Removed {2}, Error {3}' .format(added_cnt, updated_cnt, removed_cnt, len(error_files.keys())), Style.RESET_ALL) else: print('Nothing to translate or add.') """ Results """ results_dict[lc]['deleted_files'] = removed_files results_dict[lc]['added_files'] = list( set(added_files) & set(translated_files_lines.keys())) results_dict[lc]['updated_files'] = list( set(existing_files) & set(translated_files_lines.keys())) if error_files: print(error_files) results_dict[lc]['error_lines_kv'] = error_files # print(total Results) print('') t_file_cnt = \ t_line_cnt = \ file_add_cnt = \ file_add_cnt = \ file_remove_cnt = \ file_update_cnt = \ file_skip_cnt = \ 0 for lc in results_dict.keys(): result_lc = results_dict[lc] file_add_cnt += len(result_lc['added_files']) file_remove_cnt += len(result_lc['deleted_files']) file_update_cnt += len(result_lc['updated_files']) file_skip_cnt += len(result_lc['skipped_files']) for f in result_lc['added_files']: print('Added', f) for f in result_lc['deleted_files']: print('Removed', f) for f in result_lc['updated_files']: print('Updated', f) for f in result_lc['skipped_files']: print('Skiped', f) tfiles = result_lc['translated_files_lines'] if tfiles: # print('============ Results for langcode : {0} ============='.format(lc)) for f in tfiles: t_file_cnt += 1 if len(tfiles[f]): # print('', f) for key in tfiles[f]: t_line_cnt += 1 # print(key, ' = ', tfiles[f][key]) for lc in global_result_logs.keys(): print(lc) for t in global_result_logs[lc].keys(): o, b = global_result_logs[lc][t] print(o.decode('utf-8'), ' -> ', b) print('') # WARN found_warining = filter(lambda i: i or None, rget(results_dict, 'error_lines_kv')) if found_warining: print( Fore.YELLOW + '\n[!] WARNING: Found strings that contains the syntax error. Please confirm.' + Style.RESET_ALL) for a in found_warining: for k in a: print('at', k) for i in a[k]: print(' ', i) # VERIFY FAILED verified_results = filter(lambda i: i or None, rget(results_dict, 'verified_result')) if verified_results and len(verified_results): print( Fore.GREEN + '\n[i] VERIFIED RESULTS: Matched ratio via reversed translation results. Please confirm.' + Style.RESET_ALL) for lc in results_dict: print(lc) vr = results_dict[lc]['verified_result'] for k in vr: vd = vr[k] status_msg = Fore.RED + '(Ignored) ' + Style.RESET_ALL if __IGNORE_UNVERIFIED_RESULTS__ and vd[ 'ratio'] <= __RATIO_TO_IGNORE_UNVERIFIED_RESULTS__ else '' print(' {}{}: {} -> {} -> {}, Matched: {}%'.format( status_msg, k, vd['original'], vd['translated'], vd['reversed'], str(vd['ratio']))) print('') if file_add_cnt or file_update_cnt or file_remove_cnt or file_skip_cnt: print('Total New Translated Strings : {0}'.format(t_line_cnt)) print( 'Changed Files Total : Added {0}, Updated {1}, Removed {2}, Skipped {3}' .format(file_add_cnt, file_update_cnt, file_remove_cnt, file_skip_cnt)) print("Synchronized.") else: print( "All strings are already synchronized. Nothing to translate or add." ) return
def strings_obj_from_file(file): return strparser.parse_strings(filename=file)