|
| 1 | +import urllib.request |
| 2 | +import re |
| 3 | +import os |
| 4 | +import json5 |
| 5 | +import xml.etree.ElementTree as ET |
| 6 | +from mdutils.mdutils import MdUtils |
| 7 | +import pandas as pd |
| 8 | + |
| 9 | +def get_languages(): |
| 10 | + with urllib.request.urlopen('https://raw.githubusercontent.com/vcmi/vcmi/develop/lib/Languages.h') as f: |
| 11 | + src = f.read().decode('utf-8') |
| 12 | + languages = [x for x in re.findall(r"{ ?\"([\w]*)?\" ?,", src, re.IGNORECASE) if "other" not in x] |
| 13 | + return languages |
| 14 | + |
| 15 | +def get_base_mod(): |
| 16 | + return json5.loads(urllib.request.urlopen('https://raw.githubusercontent.com/vcmi/vcmi/develop/Mods/vcmi/mod.json').read()) |
| 17 | + |
| 18 | +def base_mod_existing(languages): |
| 19 | + vcmi_base_mod = get_base_mod() |
| 20 | + return {value:(value in vcmi_base_mod) for value in languages} |
| 21 | + |
| 22 | +def base_mod_ratio(languages): |
| 23 | + base_mod = get_base_mod() |
| 24 | + translation_english = json5.loads(urllib.request.urlopen('https://raw.githubusercontent.com/vcmi/vcmi/develop/Mods/vcmi/' + base_mod["translations"][0]).read()) |
| 25 | + |
| 26 | + data = {} |
| 27 | + |
| 28 | + for language in [key for key, value in base_mod_existing(languages).items() if value == True]: |
| 29 | + translation = json5.loads(urllib.request.urlopen('https://raw.githubusercontent.com/vcmi/vcmi/develop/Mods/vcmi/' + next(value for key, value in base_mod.items() if key == language)["translations"][0]).read()) |
| 30 | + count_equal = 0 |
| 31 | + count_difference = 0 |
| 32 | + count_only_english = 0 |
| 33 | + for key, value in translation_english.items(): |
| 34 | + if key not in translation: |
| 35 | + count_only_english += 1 |
| 36 | + continue |
| 37 | + if translation[key] == value: |
| 38 | + count_equal += 1 |
| 39 | + else: |
| 40 | + count_difference += 1 |
| 41 | + ratio = (count_difference + count_equal) / len(translation_english) |
| 42 | + data[language] = {"ratio": ratio, "count_equal": count_equal, "count_difference": count_difference, "count_only_english": count_only_english} |
| 43 | + return data |
| 44 | + |
| 45 | +def get_mod_repo(): |
| 46 | + settings_schema = json5.loads(urllib.request.urlopen("https://raw.githubusercontent.com/vcmi/vcmi/develop/config/schemas/settings.json").read()) |
| 47 | + vcmi_mod_url = settings_schema["properties"]["launcher"]["properties"]["defaultRepositoryURL"]["default"] |
| 48 | + vcmi_mods = json5.loads(urllib.request.urlopen(vcmi_mod_url).read()) |
| 49 | + return vcmi_mods |
| 50 | + |
| 51 | +def get_translation_mods(): |
| 52 | + vcmi_translation_mods = {} |
| 53 | + |
| 54 | + vcmi_mods = get_mod_repo() |
| 55 | + |
| 56 | + for key, value in vcmi_mods.items(): |
| 57 | + url = value["mod"].replace(" ", "%20") |
| 58 | + mod = json5.loads(urllib.request.urlopen(url).read()) |
| 59 | + if "language" in mod: |
| 60 | + vcmi_translation_mods[mod["language"]] = (url, mod) |
| 61 | + |
| 62 | + return vcmi_translation_mods |
| 63 | + |
| 64 | +def get_translation_mods_translation(): |
| 65 | + translation_mods = get_translation_mods() |
| 66 | + data = {} |
| 67 | + for key, value in translation_mods.items(): |
| 68 | + tmp = {} |
| 69 | + for item in value[1]["translations"]: |
| 70 | + base_url = value[0].rsplit('/', 1)[0] + "/content/" |
| 71 | + try: |
| 72 | + tmp_str = urllib.request.urlopen(base_url + item).read() |
| 73 | + except: |
| 74 | + tmp_str = urllib.request.urlopen((base_url + item).replace("content", "Content").replace("config", "Config")).read() |
| 75 | + tmp |= json5.loads(tmp_str) |
| 76 | + data[key] = tmp |
| 77 | + return data |
| 78 | + |
| 79 | +def translation_mod_ratio(translation_mods_translation): |
| 80 | + translation_english = translation_mods_translation["english"] |
| 81 | + |
| 82 | + data = {} |
| 83 | + |
| 84 | + for language in [key for key, value in translation_mods_translation.items() if key != "english"]: |
| 85 | + data_ns = {} |
| 86 | + namespaces = [None, "map", "campaign"] |
| 87 | + for namespace in namespaces: |
| 88 | + translation = translation_mods_translation[language] |
| 89 | + count_equal = 0 |
| 90 | + count_difference = 0 |
| 91 | + count_only_english = 0 |
| 92 | + for key, value in translation_english.items(): |
| 93 | + if key.split(".", 1)[0] == namespace or (namespace == None and key.split(".", 1)[0] not in namespaces): |
| 94 | + if key not in translation: |
| 95 | + count_only_english += 1 |
| 96 | + continue |
| 97 | + if translation[key] == value: |
| 98 | + count_equal += 1 |
| 99 | + else: |
| 100 | + count_difference += 1 |
| 101 | + ratio = (count_difference + count_equal) / (count_only_english + count_difference + count_equal) |
| 102 | + data_ns[namespace] = {"ratio": ratio, "count_equal": count_equal, "count_difference": count_difference, "count_only_english": count_only_english} |
| 103 | + data[language] = data_ns |
| 104 | + return data |
| 105 | + |
| 106 | +def get_qt_translations(languages): |
| 107 | + data = {} |
| 108 | + |
| 109 | + for language in [key for key, value in base_mod_existing(languages).items() if value == True]: |
| 110 | + data_type = {} |
| 111 | + for type in ["mapeditor", "launcher"]: |
| 112 | + count_translated = 0 |
| 113 | + count_untranslated = 0 |
| 114 | + tmp_str = urllib.request.urlopen("https://raw.githubusercontent.com/vcmi/vcmi/develop/" + type + "/translation/" + language + ".ts").read() |
| 115 | + root = ET.fromstring(tmp_str) |
| 116 | + for item_context in root.iter('context'): |
| 117 | + for item_message in item_context.iter('message'): |
| 118 | + if list(item_message.iter('translation'))[0].get("type") == None: |
| 119 | + count_translated += 1 |
| 120 | + else: |
| 121 | + count_untranslated += 1 |
| 122 | + ratio = (count_translated) / (count_translated + count_untranslated) |
| 123 | + data_type[type] = {"ratio": ratio, "count_translated": count_translated, "count_untranslated": count_untranslated} |
| 124 | + data[language] = data_type |
| 125 | + return data |
| 126 | + |
| 127 | +def get_mod_translations(languages): |
| 128 | + vcmi_mods = get_mod_repo() |
| 129 | + data = {} |
| 130 | + for key, value in vcmi_mods.items(): |
| 131 | + url = value["mod"].replace(" ", "%20") |
| 132 | + mod = json5.loads(urllib.request.urlopen(url).read()) |
| 133 | + if "language" not in mod: |
| 134 | + found_languages = [] |
| 135 | + for language in languages: |
| 136 | + if language in mod: |
| 137 | + found_languages.append(language) |
| 138 | + data[key] = found_languages |
| 139 | + return data |
| 140 | + |
| 141 | +def create_md(): |
| 142 | + languages = get_languages() |
| 143 | + languages_translate = [x for x in languages if x != "english"] |
| 144 | + |
| 145 | + md = MdUtils(file_name='_') |
| 146 | + |
| 147 | + def format_value(percent): |
| 148 | + if percent < 0.7: |
| 149 | + return "$\\color{red}{\\textsf{" + str(round(percent * 100, 1)) + " \\%" + "}}$" |
| 150 | + elif percent < 0.9: |
| 151 | + return "$\\color{yellow}{\\textsf{" + str(round(percent * 100, 1)) + " \\%" + "}}$" |
| 152 | + else: |
| 153 | + return "$\\color{green}{\\textsf{" + str(round(percent * 100, 1)) + " \\%" + "}}$" |
| 154 | + |
| 155 | + md.new_header(level=1, title="VCMI translations") |
| 156 | + md.new_line("This tables shows the current translation progress of VCMI. Contains only the state of the translation strings, not for the assets.") |
| 157 | + |
| 158 | + md.new_header(level=2, title="Main translation") |
| 159 | + tmp = base_mod_ratio(languages_translate) |
| 160 | + df = pd.DataFrame({"Area": "Main-Repo"} | {x:([format_value(tmp[x]["ratio"])] if x in tmp else [format_value(0)]) for x in languages_translate}) |
| 161 | + tmp = translation_mod_ratio(get_translation_mods_translation()) |
| 162 | + for area in list(tmp.values())[0].keys(): |
| 163 | + df = pd.concat([df, pd.DataFrame({"Area": "Mod-Repo" + (' main' if area == None else ' ' + area)} | {x:([format_value(tmp[x][area]["ratio"])] if x in tmp else [format_value(0)]) for x in languages_translate})], ignore_index=True) |
| 164 | + df = df.T.reset_index().T |
| 165 | + md.new_table(columns=df.shape[1], rows=df.shape[0], text=df.to_numpy().flatten(), text_align='center') |
| 166 | + |
| 167 | + md.new_header(level=2, title="QT tools translation") |
| 168 | + tmp = get_qt_translations(languages_translate) |
| 169 | + df = pd.DataFrame(columns=["Tool"] + languages_translate) |
| 170 | + for tool in list(tmp.values())[0].keys(): |
| 171 | + df = pd.concat([df, pd.DataFrame({"Tool": tool} | {x:[format_value(tmp[x][tool]["ratio"])] if x in tmp else [format_value(0)] for x in languages_translate})], ignore_index=True) |
| 172 | + df = df.T.reset_index().T |
| 173 | + md.new_table(columns=df.shape[1], rows=df.shape[0], text=df.to_numpy().flatten(), text_align='center') |
| 174 | + |
| 175 | + md.new_header(level=2, title="Mod translations") |
| 176 | + tmp = get_mod_translations(languages_translate) |
| 177 | + df = pd.DataFrame(columns=["Mod"] + languages_translate) |
| 178 | + for mod in tmp: |
| 179 | + df = pd.concat([df, pd.DataFrame({"Mod": mod} | {x:["x" if x in tmp[mod] else ""] for x in languages_translate})], ignore_index=True) |
| 180 | + df = df.T.reset_index().T |
| 181 | + md.new_table(columns=df.shape[1], rows=df.shape[0], text=df.to_numpy().flatten(), text_align='center') |
| 182 | + |
| 183 | + return md.get_md_text() |
| 184 | + |
| 185 | +if __name__ == "__main__": |
| 186 | + with open(os.path.join('.', 'README.md'), "w") as f: |
| 187 | + f.write(create_md()) |
0 commit comments