ya2 · news · projects · code · about

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