comparison i18n/check-translation.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 19fc5a986669
children c102b704edb5
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
8 import polib 8 import polib
9 9
10 scanners = [] 10 scanners = []
11 checkers = [] 11 checkers = []
12 12
13
13 def scanner(): 14 def scanner():
14 def decorator(func): 15 def decorator(func):
15 scanners.append(func) 16 scanners.append(func)
16 return func 17 return func
18
17 return decorator 19 return decorator
20
18 21
19 def levelchecker(level, msgidpat): 22 def levelchecker(level, msgidpat):
20 def decorator(func): 23 def decorator(func):
21 if msgidpat: 24 if msgidpat:
22 match = re.compile(msgidpat).search 25 match = re.compile(msgidpat).search
23 else: 26 else:
24 match = lambda msgid: True 27 match = lambda msgid: True
25 checkers.append((func, level)) 28 checkers.append((func, level))
26 func.match = match 29 func.match = match
27 return func 30 return func
31
28 return decorator 32 return decorator
33
29 34
30 def match(checker, pe): 35 def match(checker, pe):
31 """Examine whether POEntry "pe" is target of specified checker or not 36 """Examine whether POEntry "pe" is target of specified checker or not
32 """ 37 """
33 if not checker.match(pe.msgid): 38 if not checker.match(pe.msgid):
37 for tc in pe.tcomment.split(): 42 for tc in pe.tcomment.split():
38 if nochecker == tc: 43 if nochecker == tc:
39 return 44 return
40 return True 45 return True
41 46
47
42 #################### 48 ####################
49
43 50
44 def fatalchecker(msgidpat=None): 51 def fatalchecker(msgidpat=None):
45 return levelchecker('fatal', msgidpat) 52 return levelchecker('fatal', msgidpat)
53
46 54
47 @fatalchecker(r'\$\$') 55 @fatalchecker(r'\$\$')
48 def promptchoice(pe): 56 def promptchoice(pe):
49 """Check translation of the string given to "ui.promptchoice()" 57 """Check translation of the string given to "ui.promptchoice()"
50 58
68 if [c for c, i in indices if i == -1]: 76 if [c for c, i in indices if i == -1]:
69 yield "msgstr has invalid choice missing '&'" 77 yield "msgstr has invalid choice missing '&'"
70 if [c for c, i in indices if len(c) == i + 1]: 78 if [c for c, i in indices if len(c) == i + 1]:
71 yield "msgstr has invalid '&' followed by none" 79 yield "msgstr has invalid '&' followed by none"
72 80
81
73 deprecatedpe = None 82 deprecatedpe = None
83
84
74 @scanner() 85 @scanner()
75 def deprecatedsetup(pofile): 86 def deprecatedsetup(pofile):
76 pes = [p for p in pofile if p.msgid == '(DEPRECATED)' and p.msgstr] 87 pes = [p for p in pofile if p.msgid == '(DEPRECATED)' and p.msgstr]
77 if len(pes): 88 if len(pes):
78 global deprecatedpe 89 global deprecatedpe
79 deprecatedpe = pes[0] 90 deprecatedpe = pes[0]
91
80 92
81 @fatalchecker(r'\(DEPRECATED\)') 93 @fatalchecker(r'\(DEPRECATED\)')
82 def deprecated(pe): 94 def deprecated(pe):
83 """Check for DEPRECATED 95 """Check for DEPRECATED
84 >>> ped = polib.POEntry( 96 >>> ped = polib.POEntry(
107 >>> pe = polib.POEntry( 119 >>> pe = polib.POEntry(
108 ... msgid = 'Something (DEPRECATED, foo bar)', 120 ... msgid = 'Something (DEPRECATED, foo bar)',
109 ... msgstr= 'something (DETACERPED, foo bar)') 121 ... msgstr= 'something (DETACERPED, foo bar)')
110 >>> match(deprecated, pe) 122 >>> match(deprecated, pe)
111 """ 123 """
112 if not ('(DEPRECATED)' in pe.msgstr or 124 if not (
113 (deprecatedpe and 125 '(DEPRECATED)' in pe.msgstr
114 deprecatedpe.msgstr in pe.msgstr)): 126 or (deprecatedpe and deprecatedpe.msgstr in pe.msgstr)
127 ):
115 yield "msgstr inconsistently translated (DEPRECATED)" 128 yield "msgstr inconsistently translated (DEPRECATED)"
116 129
130
117 #################### 131 ####################
132
118 133
119 def warningchecker(msgidpat=None): 134 def warningchecker(msgidpat=None):
120 return levelchecker('warning', msgidpat) 135 return levelchecker('warning', msgidpat)
136
121 137
122 @warningchecker() 138 @warningchecker()
123 def taildoublecolons(pe): 139 def taildoublecolons(pe):
124 """Check equality of tail '::'-ness between msgid and msgstr 140 """Check equality of tail '::'-ness between msgid and msgstr
125 141
139 tail '::'-ness differs between msgid and msgstr 155 tail '::'-ness differs between msgid and msgstr
140 """ 156 """
141 if pe.msgid.endswith('::') != pe.msgstr.endswith('::'): 157 if pe.msgid.endswith('::') != pe.msgstr.endswith('::'):
142 yield "tail '::'-ness differs between msgid and msgstr" 158 yield "tail '::'-ness differs between msgid and msgstr"
143 159
160
144 @warningchecker() 161 @warningchecker()
145 def indentation(pe): 162 def indentation(pe):
146 """Check equality of initial indentation between msgid and msgstr 163 """Check equality of initial indentation between msgid and msgstr
147 164
148 This may report unexpected warning, because this doesn't aware 165 This may report unexpected warning, because this doesn't aware
157 idindent = len(pe.msgid) - len(pe.msgid.lstrip()) 174 idindent = len(pe.msgid) - len(pe.msgid.lstrip())
158 strindent = len(pe.msgstr) - len(pe.msgstr.lstrip()) 175 strindent = len(pe.msgstr) - len(pe.msgstr.lstrip())
159 if idindent != strindent: 176 if idindent != strindent:
160 yield "initial indentation width differs betweeen msgid and msgstr" 177 yield "initial indentation width differs betweeen msgid and msgstr"
161 178
179
162 #################### 180 ####################
163 181
182
164 def check(pofile, fatal=True, warning=False): 183 def check(pofile, fatal=True, warning=False):
165 targetlevel = { 'fatal': fatal, 'warning': warning } 184 targetlevel = {'fatal': fatal, 'warning': warning}
166 targetcheckers = [(checker, level) 185 targetcheckers = [
167 for checker, level in checkers 186 (checker, level) for checker, level in checkers if targetlevel[level]
168 if targetlevel[level]] 187 ]
169 if not targetcheckers: 188 if not targetcheckers:
170 return [] 189 return []
171 190
172 detected = [] 191 detected = []
173 for checker in scanners: 192 for checker in scanners:
174 checker(pofile) 193 checker(pofile)
175 for pe in pofile.translated_entries(): 194 for pe in pofile.translated_entries():
176 errors = [] 195 errors = []
177 for checker, level in targetcheckers: 196 for checker, level in targetcheckers:
178 if match(checker, pe): 197 if match(checker, pe):
179 errors.extend((level, checker.__name__, error) 198 errors.extend(
180 for error in checker(pe)) 199 (level, checker.__name__, error) for error in checker(pe)
200 )
181 if errors: 201 if errors:
182 detected.append((pe, errors)) 202 detected.append((pe, errors))
183 return detected 203 return detected
184 204
205
185 ######################################## 206 ########################################
186 207
187 if __name__ == "__main__": 208 if __name__ == "__main__":
188 import sys 209 import sys
189 import optparse 210 import optparse
190 211
191 optparser = optparse.OptionParser("""%prog [options] pofile ... 212 optparser = optparse.OptionParser(
213 """%prog [options] pofile ...
192 214
193 This checks Mercurial specific translation problems in specified 215 This checks Mercurial specific translation problems in specified
194 '*.po' files. 216 '*.po' files.
195 217
196 Each detected problems are shown in the format below:: 218 Each detected problems are shown in the format below::
205 be separated by whitespaces:: 227 be separated by whitespaces::
206 228
207 # no-foo-check 229 # no-foo-check
208 msgid = "....." 230 msgid = "....."
209 msgstr = "....." 231 msgstr = "....."
210 """) 232 """
211 optparser.add_option("", "--warning", 233 )
212 help="show also warning level problems", 234 optparser.add_option(
213 action="store_true") 235 "",
214 optparser.add_option("", "--doctest", 236 "--warning",
215 help="run doctest of this tool, instead of check", 237 help="show also warning level problems",
216 action="store_true") 238 action="store_true",
239 )
240 optparser.add_option(
241 "",
242 "--doctest",
243 help="run doctest of this tool, instead of check",
244 action="store_true",
245 )
217 (options, args) = optparser.parse_args() 246 (options, args) = optparser.parse_args()
218 247
219 if options.doctest: 248 if options.doctest:
220 import os 249 import os
250
221 if 'TERM' in os.environ: 251 if 'TERM' in os.environ:
222 del os.environ['TERM'] 252 del os.environ['TERM']
223 import doctest 253 import doctest
254
224 failures, tests = doctest.testmod() 255 failures, tests = doctest.testmod()
225 sys.exit(failures and 1 or 0) 256 sys.exit(failures and 1 or 0)
226 257
227 detected = [] 258 detected = []
228 warning = options.warning 259 warning = options.warning
229 for f in args: 260 for f in args:
230 detected.extend((f, pe, errors) 261 detected.extend(
231 for pe, errors in check(polib.pofile(f), 262 (f, pe, errors)
232 warning=warning)) 263 for pe, errors in check(polib.pofile(f), warning=warning)
264 )
233 if detected: 265 if detected:
234 for f, pe, errors in detected: 266 for f, pe, errors in detected:
235 for level, checker, error in errors: 267 for level, checker, error in errors:
236 sys.stderr.write('%s:%d:%s(%s): %s\n' 268 sys.stderr.write(
237 % (f, pe.linenum, level, checker, error)) 269 '%s:%d:%s(%s): %s\n'
270 % (f, pe.linenum, level, checker, error)
271 )
238 sys.exit(1) 272 sys.exit(1)