forked from Podshot/MCEdit-Unified
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mclangres.py
307 lines (293 loc) · 13.5 KB
/
mclangres.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# -*- coding: utf_8 -*-
#
# mclangres.py
#
# Collect the Minecraft internal translations.
#
"""
Uses `.minecraft/assets/indexes/[version].json`. The version is the highest
found by default.
"""
import re
import os
import codecs
from distutils.version import LooseVersion
from directories import getMinecraftLauncherDirectory, getDataDir, getDataFile
import logging
log = logging.getLogger(__name__)
indexesDirectory = os.path.join(getMinecraftLauncherDirectory(), 'assets', 'indexes')
objectsDirectory = os.path.join(getMinecraftLauncherDirectory(), 'assets', 'objects')
enRes = {}
serNe = {}
langRes = {}
serGnal = {}
enMisc = {}
csimNe = {}
langMisc = {}
csimGnal = {}
# Shall this be maintained in an external resource?
excludedEntries = ['tile.flower1.name',]
# Used to track untranslated and out dated MCEdit resources.
# Set it to true to generate/add entries to 'missingmclangres.txt' in MCEdit folder.
# Note that some strings may be falsely reported. (Especialy a '7 (Source)' one...)
# ! ! ! Please, pay attention to disable this befor releasing ! ! !
report_missing = False
def getResourceName(name, data):
match = re.findall('"minecraft/lang/%s.lang":[ ]\{\b*.*?"hash":[ ]"(.*?)",' % name, data, re.I|re.DOTALL)
if match:
return match[0]
else:
log.debug('Could not find %s resource name.' % name)
def findResourceFile(name, basedir):
for root, dirs, files in os.walk(basedir):
if name in files:
return os.path.join(basedir, root, name)
def buildResources(version=None, lang=None):
"""Loads the resource files and builds the resource dictionnaries.
Four dictionnaries are built. Two for the refering language (English), and two for the language to be used.
They are 'reversed' dictionnaries; the {foo: bar} pairs of one are the {bar: foo} of the other one."""
log.debug('Building Minecraft language resources...')
global enRes
global serNe
global langRes
global serGnal
global enMisc
global csimEn
global langMisc
global csimGnal
enRes = {}
serNe = {}
langRes = {}
serGnal = {}
enMisc = {}
csimEn = {}
langMisc = {}
csimGnal = {}
if not os.path.exists(indexesDirectory) or not os.path.exists(objectsDirectory):
log.debug('Minecraft installation directory is not valid.')
log.debug('Impossible to load the game language resources.')
return
_versions = os.listdir(indexesDirectory)
if 'legacy.json' in _versions:
_versions.remove('legacy.json')
if len(_versions) == 0:
log.debug("No valid versions found in minecraft install directory")
return
# Sort the version so '1.8' comes after '1.10'.
versions = [" "]
for ver_str in _versions:
v1 = LooseVersion(ver_str)
idx = -1
for i, cur_ver in enumerate(versions):
v2 = LooseVersion(cur_ver)
if v1>= v2:
break
versions.insert(i, ver_str)
versions = versions[:-1]
version_file = "%s.json" % version
fName = None
if version_file in versions:
fName = os.path.join(indexesDirectory, version_file)
elif version:
# Let's try to find a corresponding file by reducing the name.
# E.g: 1.10.2 don't have an asset definition file, but 1.10 have. All the same for the pre-releases...
if '-' in version:
version = version.split('-')[0]
while '.' in version:
version = version.split('.')
version_file = "%s.json" % version
if version_file in versions:
fName = os.path.join(indexesDirectory, version_file)
break
if not fName:
fName = os.path.join(indexesDirectory, versions[-1])
log.debug('Using %s' % fName)
data = open(fName).read()
name = getResourceName('en_GB', data)
if name:
fName = os.path.join(objectsDirectory, name[:2], name)
if not os.path.exists(fName):
fName = findResourceFile(name, objectsDirectory)
if not fName:
log.debug('Can\'t get the resource %s.' % name)
log.debug('Nothing built. Aborted')
return
log.debug('Found %s' % name)
lines = codecs.open(fName, encoding='utf_8').readlines()
for line in lines:
if line.split('.')[0] in ['book', 'enchantment', 'entity', 'gameMode', 'generator', 'item', 'tile'] and line.split('=')[0].strip() not in excludedEntries:
enRes[line.split('=', 1)[-1].strip()] = line.split('=', 1)[0].strip()
serNe[line.split('=', 1)[0].strip()] = line.split('=', 1)[-1].strip()
#lines = codecs.open(os.path.join(getDataDir(), 'Items', 'en_GB'), encoding='utf_8')
lines = codecs.open(getDataFile('Items', 'en_GB'), encoding='utf_8')
for line in lines:
if line.split('.')[0] in ['book', 'enchantment', 'entity', 'gameMode', 'generator', 'item', 'tile'] and line.split('=')[0].strip() not in excludedEntries:
enRes[line.split('=', 1)[-1].strip()] = line.split('=', 1)[0].strip()
serNe[line.split('=', 1)[0].strip()] = line.split('=', 1)[-1].strip()
else:
enMisc[line.split('=', 1)[-1].strip()] = line.split('=', 1)[0].strip()
csimNe[line.split('=', 1)[0].strip()] = line.split('=', 1)[-1].strip()
log.debug('... Loaded!')
else:
return
if not lang:
lang = 'en_GB'
log.debug('Looking for %s resources.' % lang)
name = getResourceName(lang, data)
if not name:
lang = 'en_GB'
name = getResourceName(lang, data)
if name:
fName = os.path.join(objectsDirectory, name[:2], name)
if not os.path.exists(fName):
fName = findResourceFile(name, objectsDirectory)
if not fName:
log.debug('Can\'t get the resource %s.' % name)
return
log.debug('Found %s...' % name)
lines = codecs.open(fName, encoding='utf_8').readlines()
for line in lines:
if line.split('.')[0] in ['book', 'enchantment', 'entity', 'gameMode', 'generator', 'item', 'tile'] and line.split('=')[0].strip() not in excludedEntries:
langRes[line.split('=', 1)[0].strip()] = line.split('=', 1)[-1].strip()
serGnal[line.split('=', 1)[-1].strip()] = line.split('=', 1)[0].strip()
#if os.path.exists(os.path.join(getDataDir(), 'Items', lang)):
if os.path.exists(getDataFile('Items', lang)):
log.debug("Found Items/%s" % lang)
#lines = codecs.open(os.path.join(getDataDir(), 'Items', lang), encoding='utf_8')
lines = codecs.open(getDataFile('Items', lang), encoding='utf_8')
for line in lines:
if line.split('.')[0] in ['book', 'enchantment', 'entity', 'gameMode', 'generator', 'item', 'tile'] and line.split('=')[0].strip() not in excludedEntries:
langRes[line.split('=', 1)[0].strip()] = line.split('=', 1)[-1].strip()
serGnal[line.split('=', 1)[-1].strip()] = line.split('=', 1)[0].strip()
else:
langMisc[line.split('=', 1)[0].strip()] = line.split('=', 1)[-1].strip()
csimGnal[line.split('=', 1)[-1].strip()] = line.split('=', 1)[0].strip()
log.debug('... Loaded!')
else:
return
def compound(char, string, pair=None):
if pair is None:
if char in '{[(':
pair = '}])'['{[('.index(char)]
else:
pair = char
name, misc = string.split(char, 1)
name = name.strip()
misc = [a.strip() for a in misc.strip()[:-1].split(',')]
if (name not in enRes.keys() and name not in langRes.values()) and (name not in enMisc.keys() and name not in langMisc.values()):
addMissing(name)
head = langRes.get(enRes.get(name, name), name)
for i in xrange(len(misc)):
if ' ' in misc[i]:
if langMisc.get(enMisc.get(misc[i], False), False):
misc[i] = langMisc.get(enMisc.get(misc[i], misc[i]), misc[i])
elif langRes.get(enRes.get(misc[i], False), False):
misc[i] = langRes.get(enRes.get(misc[i], misc[i]), misc[i])
else:
stop = [False, False]
for j in xrange(1, misc[i].count(' ') + 1):
elems = misc[i].rsplit(' ', j)
if not stop[0]:
h = elems[0]
if langMisc.get(enMisc.get(h, False), False):
h = langMisc.get(enMisc.get(h, h), h)
stop[0] = True
elif langRes.get(enRes.get(h, False), False):
h = langRes.get(enRes.get(h, h), h)
stop[0] = True
if not stop[1]:
t = u' '.join(elems[1:])
if langMisc.get(enMisc.get(t, False), False):
t = langMisc.get(enMisc.get(t, t), t)
stop[1] = True
elif langRes.get(enRes.get(t, False), False):
t = langRes.get(enRes.get(t, t), t)
stop[1] = True
if stop[0]:
stop[1] = True
misc[i] = u' '.join((h, t))
if (h not in enRes.keys() and h not in langRes.values()) and (h not in enMisc.keys() and h not in langMisc.values()):
addMissing(h, 'misc')
if (t not in enRes.keys() and t not in langRes.values()) and (t not in enMisc.keys() and t not in langMisc.values()):
addMissing(t, 'misc')
elif u'/' in misc[i]:
misc[i] = u'/'.join([langMisc.get(enMisc.get(a, a), translate(a)) for a in misc[i].split('/')])
elif '-' in misc[i]:
misc[i] = u'-'.join([langMisc.get(enMisc.get(a, a), translate(a)) for a in misc[i].split('-')])
elif '_' in misc[i]:
misc[i] = u'_'.join([langMisc.get(enMisc.get(a, a), translate(a)) for a in misc[i].split('_')])
else:
misc[i] = langRes.get(enRes.get(misc[i], misc[i]), misc[i])
tail = u'{0}{1}{2}'.format(char, u', '.join([langMisc.get(enMisc.get(a, a), a) for a in misc]), pair)
return u' '.join((head, tail))
if report_missing:
def addMissing(name, cat='base'):
n = u''
for a in name:
if a == ' ' or a.isalnum():
n += a
elems = n.split(' ', 1)
head = elems[0].lower()
tail = ''
if len(elems) > 1:
tail = ''.join([a.capitalize() for a in elems[1].split(' ') if not a.isdigit()])
if not n.isdigit():
line = 'missing.{0}.{1}{2}={3}\n'.format(cat, head, tail, name)
#f = codecs.open(os.path.join(getDataDir(), 'missingmclangres.txt'), 'a+', encoding='utf_8')
f = codecs.open(getDataFile('missingmclangres.txt'), 'a+', encoding='utf_8')
if line not in f.read():
f.write(line)
f.close()
else:
def addMissing(*args, **kwargs): return
def translate(name):
"""Returns returns the translation of `name`, or `name` if no translation found.
Can handle composed strings like: 'string_present_in_translations (other_string_1, other_string_2)'.
Note that, in this case, the returned string may be partially translated."""
for c in '{[(':
if c in name:
return compound(c, name)
if report_missing:
print '*', (name not in enRes.keys() and name not in langRes.values()) and (name not in enMisc.keys() and name not in langMisc.values()), name
if (name not in enRes.keys() and name not in langRes.values()) and (name not in enMisc.keys() and name not in langMisc.values()):
addMissing(name)
return langRes.get(enRes.get(name, name), name)
def untranslate(name, case_sensitive=True):
"""Basic reverse function of `translate`."""
key = serGnal.get(name, None)
value = serNe.get(key, None)
return value or name
def search(text, untranslate=False, capitalize=True, filters=[]):
"""Search for a `text` string in the resources entries.
`filters` is a list of strings: they must be parts before the '=' sign in the resource files, or parts of.
`filters` may be regexes.
Returns a sorted list of matching elements."""
# filters may contain regexes
text = text.lower()
results = []
def get_result(l, w):
if untranslate:
if capitalize:
results.append('-'.join([b.capitalize() for b in ' '.join([a.capitalize() for a in serNe[w].split(' ')]).split('-')]))
else:
results.append(serNe[w].lower())
else:
if capitalize:
results.append('-'.join([b.capitalize() for b in ' '.join([a.capitalize() for a in l.split(' ')]).split('-')]))
else:
results.append(l.lower())
for k, v in serGnal.items():
if text in k.lower():
if not filters or map(lambda (x,y):re.match(x,y), zip(filters, [v] * len(filters))) != [None, None]:
if untranslate:
if capitalize:
results.append('-'.join([b.capitalize() for b in ' '.join([a.capitalize() for a in serNe[v].split(' ')]).split('-')]))
else:
results.append(serNe[v].lower())
else:
if capitalize:
results.append('-'.join([b.capitalize() for b in ' '.join([a.capitalize() for a in k.split(' ')]).split('-')]))
else:
results.append(k.lower())
results.sort()
return results