ya2 · news · projects · code · about

fixes for building
[pmachines.git] / ya2 / build / lang.py
1 '''Tools for l10n.'''
2 from os import system, makedirs, remove, listdir
3 from os.path import exists, isfile, join
4 from shutil import move, copy
5 from json import loads
6 from polib import pofile, POEntry
7 from ya2.build.build import find_file_names, FindFileNamesArgs
8
9
10 class LanguageBuilder:
11 '''Tools for building files for l10n.'''
12
13 def __init__(self, app_name, po_path, json_path, mo_path):
14 self.__app_name = app_name
15 self.__po_path = po_path
16 self.__json_path = json_path
17 self.__mo_path = mo_path
18
19 def build(self):
20 self.__build_pot()
21 po_files = [name for name in listdir(self.__po_path)
22 if isfile(join(self.__po_path, name)) and
23 name.endswith('.po')]
24 language_codes = [f.split('.')[0] for f in po_files]
25 for l in language_codes: self.__process_language(l)
26
27 def __build_pot(self):
28 '''Builds the pot file in the lng_dir_code directory.'''
29 find_info = FindFileNamesArgs(['py'], ['tests'])
30 src_files = ' '.join(find_file_names(find_info))
31 cmd_tmpl = 'xgettext -ci18n -d {appname} -L python ' + \
32 '-o {pot_path}{appname}.pot '
33 system(cmd_tmpl.format(appname=self.__app_name, pot_path=self.__po_path) + src_files)
34 self.__add_from_json_to_pot()
35
36 def __add_from_json_to_pot(self):
37 json_files = [name for name in listdir(self.__json_path)
38 if isfile(join(self.__json_path, name)) and
39 name.endswith('.json') and
40 name != 'index.json']
41 json_strings = []
42 for json_file in json_files:
43 with open(f'{self.__json_path}{json_file}') as f:
44 json = loads(f.read())
45 json_strings += [json['name']]
46 for instruction_line in json['instructions'].split('\n'):
47 if instruction_line:
48 json_strings += [instruction_line]
49 def process_json_escape(string):
50 return bytes(string, 'utf-8').decode('unicode-escape')
51 json_strings = [process_json_escape(s) for s in json_strings]
52 json_strings = list(set(json_strings))
53 pot = pofile(f'{self.__po_path}{self.__app_name}.pot')
54 pot_ids = [entry.msgid for entry in pot]
55 for json_string in json_strings:
56 if json_string not in pot_ids:
57 entry = POEntry(msgid=json_string)
58 pot.append(entry)
59 pot.save(f'{self.__po_path}{self.__app_name}.pot')
60
61 def __process_language(self, language_code):
62 self.__merge(language_code)
63 self.__build_mo(language_code)
64
65 def __build_mo(self, language_code):
66 '''Builds the mo file in the lng_dir_code directory.'''
67 mo_template = '%s%s/LC_MESSAGES/%s.mo'
68 mo_name = mo_template % (self.__mo_path, language_code, self.__app_name)
69 lng_code = mo_name[len(self.__mo_path):].split('/')[0]
70 lng_dir = self.__mo_path + lng_code + '/LC_MESSAGES/'
71 cmd = 'msgfmt -o {lng_dir}{appname}.mo {po_path}{lng_code}.po'
72 system(cmd.format(lng_dir=lng_dir, appname=self.__app_name, po_path=self.__po_path, lng_code=lng_code))
73
74 def __merge(self, lng_code):
75 '''Merges the new strings with the previous ones.'''
76 lng_base_dir = self.__prepare(lng_code)
77 self.__do_merge(lng_base_dir, lng_code)
78 self.__postprocess(lng_code)
79
80 def __prepare(self, lng_code):
81 '''Prepares a directory for working with languages.'''
82 makedirs(self.__mo_path + lng_code + '/LC_MESSAGES', exist_ok=True)
83 lng_dir = self.__mo_path + lng_code + '/LC_MESSAGES/'
84 if not exists('assets/locale/po/' + lng_code + '.po'):
85 lines_to_fix = ['CHARSET/UTF-8', 'ENCODING/8bit']
86 [self.__fix_line(line, lng_dir)
87 for line in lines_to_fix]
88 copy(lng_dir + self.__app_name + '.pot', lng_dir + self.__app_name + '.po')
89 return lng_dir
90
91 def __fix_line(self, line, lng_dir):
92 '''Fixes po files (misaligned entries).'''
93 cmd_tmpl = "sed 's/{line}/' {lng_dir}{appname}.pot > " + \
94 "{lng_dir}{appname}tmp.po"
95 system(cmd_tmpl.format(line=line, lng_dir=lng_dir, appname=self.__app_name))
96 move(lng_dir + self.__app_name + 'tmp.po', lng_dir + self.__app_name + '.pot')
97
98 def __do_merge(self, lng_dir, lng_code):
99 '''Manages the msgmerge's invokation.'''
100 print('merge', lng_dir)
101 cmd = 'msgmerge -o {lng_dir}{appname}merge.po ' + \
102 '{tgt_path}{lng_code}.po {tgt_path}{appname}.pot'
103 cmd = cmd.format(lng_dir=lng_dir, lng_code=lng_code, appname=self.__app_name,
104 tgt_path=self.__po_path)
105 system(cmd)
106 copy(lng_dir + self.__app_name + 'merge.po',
107 'assets/locale/po/%s.po' % lng_code)
108 poname_tmpl = '{lng_dir}{appname}merge.po'
109 remove(poname_tmpl.format(lng_dir=lng_dir, appname=self.__app_name))
110
111 def __postprocess(self, lng_code):
112 '''Fixes po files at the end of the building process.'''
113 lines = open('assets/locale/po/%s.po' % lng_code, 'r').readlines()
114 with open('assets/locale/po/%s.po' % lng_code, 'w') as outf:
115 for line in lines:
116 po_str = '"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\\n"\n'
117 outf.write(po_str if line.startswith(po_str[:20]) else line)