forked from OpenRCT2/objects
-
Notifications
You must be signed in to change notification settings - Fork 0
/
language_load.py
executable file
·178 lines (154 loc) · 7.17 KB
/
language_load.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
#!/usr/bin/env python3
"""
Imports translations into OpenRCT2's JSON objects given a language and an input file
"""
import argparse
import glob
import json
import os
import re
import sys
from languages import SUPPORTED_LANGUAGES
def dir_path(string):
""" Checks for a valid dir_path """
if os.path.isdir(string):
return string
raise NotADirectoryError(string)
def get_arg_parser():
""" Command line arguments """
parser = argparse.ArgumentParser(description=\
'Imports translations into OpenRCT2\'s JSON objects.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-o', '--objects', default="objects", help='JSON objects directory')
parser.add_argument('-f', '--fallback', default="en-GB",\
help='Fallback language to check against', choices=SUPPORTED_LANGUAGES)
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument('-i', '--input', help='Translation dump file to import from')
input_group.add_argument('-d', '--dir', type=dir_path,\
help='Directory with translation dump files to import from')
language_group = parser.add_mutually_exclusive_group(required=True)
language_group.add_argument('-l', '--language', choices=SUPPORTED_LANGUAGES,\
help='Language that is being translated, e.g. ja-JP')
language_group.add_argument('-a', '--all-languages', action='store_true')
parser.add_argument('-v', '--verbose', action='store_true', default=False,\
help='Maximize information printed on screen')
return parser
def parse_required_switch_pairs(args):
""" Make sure only valid switch pairs are used """
single_language = args.language and args.input
all_languages = args.all_languages and args.dir
if not single_language and not all_languages:
print(f"Invalid switch pair. Use '-l <lang> -i <file>' or '-a -d <target_dir>")
sys.exit()
class LessVerboseJSONEncoder(json.JSONEncoder):
""" Custom JSON Encoder that reduces output verbosity """
def iterencode(self, o, _one_shot=False):
list_lvl = 0
for string in super(LessVerboseJSONEncoder, self).iterencode(o, _one_shot=_one_shot):
if string.startswith('['):
list_lvl += 1
string = re.sub(r'\n\s*', '', string).strip()
elif list_lvl > 0:
string = re.sub(r'\n\s*', ' ', string).strip()
if string and string[-1] == ',':
string = string[:-1] + self.item_separator
elif string and string[-1] == ':':
string = string[:-1] + self.key_separator
if string.endswith(']'):
list_lvl -= 1
yield string
def update_object_translation(filename, data, file):
""" Update target object translation """
file = open(filename, "w", encoding="utf8")
json.dump(data, file, indent=4, separators=(',', ': '),
ensure_ascii=False, cls=LessVerboseJSONEncoder)
file.write("\n")
file.close()
def translatable(verbose, data):
""" Checks if the file has string content """
if 'strings' in data:
return True
if verbose:
print(f"No strings in {data['id']} -- skipping")
return False
def is_object_translated(verbose, object_id, strings_by_object):
""" Checks if there are any translations for the given file id """
if object_id in strings_by_object:
return True
if verbose:
print(f"No translations for {object_id} in dump file -- skipping")
return False
def is_key_translated(verbose, obj_id, key, object_json):
""" Checks if the given key of an object is translated in input JSON """
if key in object_json:
return True
if verbose:
print(f"No translation for {obj_id} string '{key}' in dump file -- skipping")
return False
def fallback_key_exists(verbose, fallback_language, obj_id, key, object_json):
""" Checks if there was source language to be translated from """
if fallback_language in object_json:
return True
if verbose:
print(f"No {fallback_language} reference for {obj_id} string '{key}'"
f" in dump file -- probably shouldn't exist; skipping")
return False
def translation_existed(target_lang, translations):
""" Checks if the translation for a given key existed """
if target_lang in translations:
return True
return False
def translation_changed(verbose, obj_id, key, translation, target_string):
""" Checks if the translation for a given key changed """
if target_string == translation:
if verbose:
print(f"Translation for {obj_id} string '{key}' has not changed -- skipping")
return False
return True
def update_translation(target_lang, ref_lang, verbose, filename, strings_by_object):
""" Updates an object translation, if applicable """
file = open(filename, encoding="utf8")
data = json.load(file)
file.close()
obj_id = data['id']
if not translatable(verbose, data):
return
if not is_object_translated(verbose, obj_id, strings_by_object):
return
updated = False
for string_key in data['strings']:
if not is_key_translated(verbose, obj_id, string_key, strings_by_object[obj_id]):
continue
if not fallback_key_exists(verbose, ref_lang, string_key, obj_id,
data['strings'][string_key]):
continue
previously_translated = translation_existed(target_lang, data['strings'][string_key])
if previously_translated:
translation = data['strings'][string_key][target_lang]
else:
translation = data['strings'][string_key][ref_lang]
target_string = strings_by_object[obj_id][string_key]
if translation_changed(verbose, obj_id, string_key, translation, target_string):
print(f"{target_lang}: Updating {obj_id} string '{string_key}'")
data['strings'][string_key][target_lang] = strings_by_object[obj_id][string_key]
updated = True
if updated:
update_object_translation(filename, data, file)
def load_translation(language, fallback_language, verbose, input_filename, objects):
""" Load translation from the given file into each object JSON """
in_file = open(input_filename, encoding="utf8")
strings_by_object = json.load(in_file)
in_file.close()
for filename in glob.iglob(objects + '/**/*.json', recursive=True):
update_translation(language, fallback_language, verbose, filename, strings_by_object)
def load_translations():
""" Load translations from the given files into each object JSON """
parser = get_arg_parser()
args = parser.parse_args()
parse_required_switch_pairs(args)
languages_to_extract = SUPPORTED_LANGUAGES if args.all_languages else [args.language]
for lang in languages_to_extract:
read_file_name = f'{args.dir}/{lang}.json' if args.all_languages else args.input
load_translation(lang, args.fallback, args.verbose, read_file_name, args.objects)
if __name__ == "__main__":
load_translations()