Commit | Line | Data |
---|---|---|
8ee66edd | 1 | '''Tools for l10n.''' |
2c6a6ed1 | 2 | from os import system, makedirs, remove, listdir, getcwd, chdir |
de1cfa8a | 3 | from os.path import exists, isfile, join |
8ee66edd | 4 | from shutil import move, copy |
aa577aeb FC |
5 | from json import loads |
6 | from polib import pofile, POEntry | |
a6f7e35d | 7 | from ya2.build.build import find_file_names, FindFileNamesArgs |
8ee66edd FC |
8 | |
9 | ||
10 | class LanguageBuilder: | |
11 | '''Tools for building files for l10n.''' | |
12 | ||
2c6a6ed1 | 13 | def __init__(self, app_name, po_path, json_path, mo_path, root): |
4e980d83 FC |
14 | self.__app_name = app_name |
15 | self.__po_path = po_path | |
aa577aeb | 16 | self.__json_path = json_path |
4e980d83 | 17 | self.__mo_path = mo_path |
2c6a6ed1 | 18 | self.__root = root |
4e980d83 | 19 | |
de1cfa8a | 20 | def build(self): |
2c6a6ed1 FC |
21 | orig_dir = getcwd() |
22 | chdir(self.__root) | |
de1cfa8a FC |
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) | |
2c6a6ed1 | 29 | chdir(orig_dir) |
8ee66edd | 30 | |
de1cfa8a | 31 | def __build_pot(self): |
8ee66edd | 32 | '''Builds the pot file in the lng_dir_code directory.''' |
a6f7e35d | 33 | find_info = FindFileNamesArgs(['py'], ['tests']) |
d3ef798c | 34 | src_files = ' '.join(find_file_names(find_info)) |
8ee66edd FC |
35 | cmd_tmpl = 'xgettext -ci18n -d {appname} -L python ' + \ |
36 | '-o {pot_path}{appname}.pot ' | |
4e980d83 | 37 | system(cmd_tmpl.format(appname=self.__app_name, pot_path=self.__po_path) + src_files) |
aa577aeb FC |
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 | |
88dde925 FC |
43 | name.endswith('.json') and |
44 | name != 'index.json'] | |
aa577aeb FC |
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']] | |
88dde925 FC |
50 | for instruction_line in json['instructions'].split('\n'): |
51 | if instruction_line: | |
52 | json_strings += [instruction_line] | |
aa577aeb FC |
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') | |
8ee66edd | 64 | |
de1cfa8a FC |
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/' | |
59537c34 FC |
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)) | |
de1cfa8a FC |
77 | |
78 | def __merge(self, lng_code): | |
8ee66edd | 79 | '''Merges the new strings with the previous ones.''' |
4e980d83 | 80 | lng_base_dir = self.__prepare(lng_code) |
de1cfa8a | 81 | self.__do_merge(lng_base_dir, lng_code) |
4e980d83 | 82 | self.__postprocess(lng_code) |
8ee66edd | 83 | |
4e980d83 | 84 | def __prepare(self, lng_code): |
8ee66edd | 85 | '''Prepares a directory for working with languages.''' |
4e980d83 FC |
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'): | |
8ee66edd | 89 | lines_to_fix = ['CHARSET/UTF-8', 'ENCODING/8bit'] |
4e980d83 | 90 | [self.__fix_line(line, lng_dir) |
e65a09cf | 91 | for line in lines_to_fix] |
4e980d83 | 92 | copy(lng_dir + self.__app_name + '.pot', lng_dir + self.__app_name + '.po') |
8ee66edd FC |
93 | return lng_dir |
94 | ||
4e980d83 | 95 | def __fix_line(self, line, lng_dir): |
8ee66edd FC |
96 | '''Fixes po files (misaligned entries).''' |
97 | cmd_tmpl = "sed 's/{line}/' {lng_dir}{appname}.pot > " + \ | |
98 | "{lng_dir}{appname}tmp.po" | |
4e980d83 FC |
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') | |
8ee66edd | 101 | |
de1cfa8a | 102 | def __do_merge(self, lng_dir, lng_code): |
8ee66edd FC |
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' | |
4e980d83 FC |
107 | cmd = cmd.format(lng_dir=lng_dir, lng_code=lng_code, appname=self.__app_name, |
108 | tgt_path=self.__po_path) | |
8ee66edd | 109 | system(cmd) |
4e980d83 | 110 | copy(lng_dir + self.__app_name + 'merge.po', |
e65a09cf | 111 | 'assets/locale/po/%s.po' % lng_code) |
8ee66edd | 112 | poname_tmpl = '{lng_dir}{appname}merge.po' |
4e980d83 | 113 | remove(poname_tmpl.format(lng_dir=lng_dir, appname=self.__app_name)) |
8ee66edd | 114 | |
4e980d83 | 115 | def __postprocess(self, lng_code): |
8ee66edd | 116 | '''Fixes po files at the end of the building process.''' |
58c1093d FC |
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: | |
8ee66edd FC |
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) |