1
1
import urllib .request
2
2
import re
3
+ import json_repair
3
4
import os
4
5
import json5
5
6
import xml .etree .ElementTree as ET
6
7
from mdutils .mdutils import MdUtils
7
8
import pandas as pd
8
9
10
+ # https://stackoverflow.com/a/18381470 (Onur Yıldırım, CC BY-SA 4.0)
11
+ def remove_comments (string ):
12
+ pattern = r"(\".*?\"|\'.*?\')|(/\*.*?\*/|//[^\r\n]*$)"
13
+ # first group captures quoted strings (double or single)
14
+ # second group captures comments (//single-line or /* multi-line */)
15
+ regex = re .compile (pattern , re .MULTILINE | re .DOTALL )
16
+ def _replacer (match ):
17
+ # if the 2nd group (capturing comments) is not None,
18
+ # it means we have captured a non-quoted (real) comment string.
19
+ if match .group (2 ) is not None :
20
+ return "" # so we will return empty to remove the comment
21
+ else : # otherwise, we will return the 1st group
22
+ return match .group (1 ) # captured quoted-string
23
+ return regex .sub (_replacer , string )
24
+
25
+ def load_vcmi_json (string ):
26
+ try :
27
+ obj = json5 .loads (string )
28
+ except :
29
+ tmp = remove_comments (string .decode ())
30
+ obj = json_repair .loads (tmp )
31
+
32
+ return obj
33
+
9
34
def get_languages ():
10
35
with urllib .request .urlopen ('https://raw.githubusercontent.com/vcmi/vcmi/develop/lib/Languages.h' ) as f :
11
36
src = f .read ().decode ('utf-8' )
12
37
languages = [x for x in re .findall (r"{ ?\"([\w]*)?\" ?," , src , re .IGNORECASE ) if "other" not in x ]
13
38
return languages
14
39
15
40
def get_base_mod ():
16
- return json5 . loads (urllib .request .urlopen ('https://raw.githubusercontent.com/vcmi/vcmi/develop/Mods/vcmi/mod.json' ).read ())
41
+ return load_vcmi_json (urllib .request .urlopen ('https://raw.githubusercontent.com/vcmi/vcmi/develop/Mods/vcmi/mod.json' ).read ())
17
42
18
43
def base_mod_existing (languages ):
19
44
vcmi_base_mod = get_base_mod ()
20
45
return {value :(value in vcmi_base_mod ) for value in languages }
21
46
22
47
def base_mod_ratio (languages ):
23
48
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 ())
49
+ translation_english = load_vcmi_json (urllib .request .urlopen ('https://raw.githubusercontent.com/vcmi/vcmi/develop/Mods/vcmi/' + base_mod ["translations" ][0 ]).read ())
25
50
26
51
data = {}
27
52
28
53
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 ())
54
+ translation = load_vcmi_json (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
55
count_equal = 0
31
56
count_difference = 0
32
57
count_only_english = 0
@@ -43,9 +68,9 @@ def base_mod_ratio(languages):
43
68
return data
44
69
45
70
def get_mod_repo ():
46
- settings_schema = json5 . loads (urllib .request .urlopen ("https://raw.githubusercontent.com/vcmi/vcmi/develop/config/schemas/settings.json" ).read ())
71
+ settings_schema = load_vcmi_json (urllib .request .urlopen ("https://raw.githubusercontent.com/vcmi/vcmi/develop/config/schemas/settings.json" ).read ())
47
72
vcmi_mod_url = settings_schema ["properties" ]["launcher" ]["properties" ]["defaultRepositoryURL" ]["default" ]
48
- vcmi_mods = json5 . loads (urllib .request .urlopen (vcmi_mod_url ).read ())
73
+ vcmi_mods = load_vcmi_json (urllib .request .urlopen (vcmi_mod_url ).read ())
49
74
return vcmi_mods
50
75
51
76
def get_translation_mods ():
@@ -55,7 +80,7 @@ def get_translation_mods():
55
80
56
81
for key , value in vcmi_mods .items ():
57
82
url = value ["mod" ].replace (" " , "%20" )
58
- mod = json5 . loads (urllib .request .urlopen (url ).read ())
83
+ mod = load_vcmi_json (urllib .request .urlopen (url ).read ())
59
84
if "language" in mod :
60
85
vcmi_translation_mods [mod ["language" ]] = (url , mod )
61
86
@@ -72,10 +97,34 @@ def get_translation_mods_translation():
72
97
tmp_str = urllib .request .urlopen (base_url + item ).read ()
73
98
except :
74
99
tmp_str = urllib .request .urlopen ((base_url + item ).replace ("content" , "Content" ).replace ("config" , "Config" )).read ()
75
- tmp |= json5 . loads (tmp_str )
100
+ tmp |= load_vcmi_json (tmp_str )
76
101
data [key ] = tmp
77
102
return data
78
103
104
+ def get_translation_mods_translation_assets ():
105
+ translation_mods = get_translation_mods ()
106
+ data = {}
107
+ for key , value in translation_mods .items ():
108
+ repo = re .search (r"vcmi-mods\/(.*?)\/" , value [0 ]).group (1 )
109
+ branch = re .search (repo + r"\/([^\/]*?)\/" , value [0 ]).group (1 )
110
+ files_api = "https://api.github.com/repos/vcmi-mods/" + repo + "/git/trees/" + branch + "?recursive=1"
111
+ files = [x ["path" ].lower () for x in json5 .loads (urllib .request .urlopen (files_api ).read ())["tree" ]]
112
+ files_filtered = [x for x in files if "mods/" not in x ]
113
+
114
+ files_to_translate = json5 .load (open ("files_to_translated.json" , "r" ))
115
+ files_ct = {}
116
+ files_found = {}
117
+ for file in files_to_translate :
118
+ type = re .search (r"content\/(.*?)\/" , file ).group (1 )
119
+ if type not in files_ct : files_ct [type ] = 0
120
+ if type not in files_found : files_found [type ] = 0
121
+ files_ct [type ] += 1
122
+ files_found [type ] += 1 if any ([file in x for x in files_filtered ]) else 0
123
+ files_ratio = {k : files_found [k ]/ v for k , v in files_ct .items ()}
124
+
125
+ data [key ] = files_ratio
126
+ return data
127
+
79
128
def translation_mod_ratio (translation_mods_translation ):
80
129
translation_english = translation_mods_translation ["english" ]
81
130
@@ -129,7 +178,7 @@ def get_mod_translations(languages):
129
178
data = {}
130
179
for key , value in vcmi_mods .items ():
131
180
url = value ["mod" ].replace (" " , "%20" )
132
- mod = json5 . loads (urllib .request .urlopen (url ).read ())
181
+ mod = load_vcmi_json (urllib .request .urlopen (url ).read ())
133
182
if "language" not in mod :
134
183
found_languages = []
135
184
for language in languages :
@@ -153,30 +202,33 @@ def format_value(percent):
153
202
return "$\\ color{green}{\\ textsf{" + str (round (percent * 100 , 1 )) + " \\ %" + "}}$"
154
203
155
204
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 ." )
205
+ md .new_line ("This tables shows the current translation progress of VCMI. See [here](https://github.com/vcmi/vcmi/blob/develop/docs/modders/Translations.md) how to translate VCMI. See assets for translation [here](files_to_translated.json) ( not every language need each asset) ." )
157
206
158
207
md .new_header (level = 2 , title = "Main translation" )
159
208
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 })
209
+ df = pd .DataFrame ({"Area" : "[ Main-Repo](https://github.com/vcmi/vcmi) " } | {x :([format_value (tmp [x ]["ratio" ])] if x in tmp else [format_value (0 )]) for x in languages_translate })
161
210
tmp = translation_mod_ratio (get_translation_mods_translation ())
162
211
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 )
212
+ df = pd .concat ([df , pd .DataFrame ({"Area" : "[Mod-Repo](https://github.com/vcmi-mods)" + (' game' 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 )
213
+ tmp = get_translation_mods_translation_assets ()
214
+ for area in list (tmp .values ())[0 ].keys ():
215
+ df = pd .concat ([df , pd .DataFrame ({"Area" : "[Mod-Repo](https://github.com/vcmi-mods)" + (' Assets: ' + area )} | {x :([format_value (tmp [x ][area ])] if x in tmp else [format_value (0 )]) for x in languages_translate })], ignore_index = True )
164
216
df = df .T .reset_index ().T
165
217
md .new_table (columns = df .shape [1 ], rows = df .shape [0 ], text = df .to_numpy ().flatten (), text_align = 'center' )
166
218
167
219
md .new_header (level = 2 , title = "QT tools translation" )
168
220
tmp = get_qt_translations (languages_translate )
169
221
df = pd .DataFrame (columns = ["Tool" ] + languages_translate )
170
222
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 )
223
+ df = pd .concat ([df , pd .DataFrame ({"Tool" : "[" + tool + "](https://github.com/vcmi/vcmi/tree/develop/" + tool + "/translation)" } | {x :[format_value (tmp [x ][tool ]["ratio" ])] if x in tmp else [format_value (0 )] for x in languages_translate })], ignore_index = True )
172
224
df = df .T .reset_index ().T
173
225
md .new_table (columns = df .shape [1 ], rows = df .shape [0 ], text = df .to_numpy ().flatten (), text_align = 'center' )
174
226
175
227
md .new_header (level = 2 , title = "Mod translations" )
176
228
tmp = get_mod_translations (languages_translate )
177
229
df = pd .DataFrame (columns = ["Mod" ] + languages_translate )
178
230
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 )
231
+ df = pd .concat ([df , pd .DataFrame ({"Mod" : "[" + mod + "](https://github.com/vcmi-mods/" + mod . replace ( " " , "-" ) + ")" } | {x :["x" if x in tmp [mod ] else "" ] for x in languages_translate })], ignore_index = True )
180
232
df = df .T .reset_index ().T
181
233
md .new_table (columns = df .shape [1 ], rows = df .shape [0 ], text = df .to_numpy ().flatten (), text_align = 'center' )
182
234
0 commit comments