2 from os
import system
, makedirs
, remove
, listdir
, getcwd
, chdir
3 from os
.path
import exists
, isfile
, join
4 from shutil
import move
, copy
6 from polib
import pofile
, POEntry
7 from ya2
.build
.build
import find_file_names
, FindFileNamesArgs
10 class LanguageBuilder
:
11 '''Tools for building files for l10n.'''
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
24 po_files
= [name
for name
in listdir(self
.__po
_path
)
25 if isfile(join(self
.__po
_path
, name
)) and
27 language_codes
= [f
.split('.')[0] for f
in po_files
]
28 for l
in language_codes
: self
.__process
_language
(l
)
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
()
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
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'):
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
)
63 pot
.save(f
'{self.__po_path}{self.__app_name}.pot')
65 def __process_language(self
, language_code
):
66 self
.__merge
(language_code
)
67 self
.__build
_mo
(language_code
)
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
))
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
)
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')
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')
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
)
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
))
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
:
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
)