1- # -*- coding: utf-8 -*-
1+ #!/usr/bin/env python3
22#
33# Copyright (C) 2009-2021 Sébastien Helleu <flashcode@flashtux.org>
44#
1818# along with msgcheck. If not, see <https://www.gnu.org/licenses/>.
1919#
2020
21- """
22- Classes to read and check PO (gettext) files.
23- """
21+ """Classes to read and check PO (gettext) files."""
2422
2523from __future__ import print_function
2624
2725from codecs import escape_decode
2826import os
2927import re
3028import subprocess
31- import sys
3229import tempfile
3330
3431# enchant module is optional, spelling is checked on demand
@@ -72,17 +69,13 @@ def __repr__(self):
7269 if self .idmsg == 'extract' :
7370 return self .message + '\n ---'
7471 if self .idmsg == 'compile' :
75- return '{0} \n {1}' . format ( '=' * 70 , self .message )
72+ return f' { "=" * 70 } \n { self .message } '
7673 is_list = isinstance (self .message , list )
77- count = '(%d)' % len (self .message ) if is_list else ''
78- msg = '{0}\n {1}:{2}: [{3}{4}] {5}{6}' .format (
79- '=' * 70 ,
80- self .filename ,
81- self .line ,
82- self .idmsg ,
83- count ,
84- '(fuzzy) ' if self .fuzzy else '' ,
85- ', ' .join (self .message ) if is_list else self .message )
74+ count = f'({ len (self .message )} )' if is_list else ''
75+ str_fuzzy = '(fuzzy) ' if self .fuzzy else ''
76+ str_msg = ', ' .join (self .message ) if is_list else self .message
77+ msg = (f'{ "=" * 70 } \n { self .filename } :{ self .line } : '
78+ f'[{ self .idmsg } { count } ] { str_fuzzy } { str_msg } ' )
8679 if self .mid :
8780 msg += '\n ---\n ' + self .mid
8881 if self .mstr :
@@ -126,19 +119,16 @@ def __init__(self, filename, line, msg, charset, fuzzy, fmt, noqa):
126119 self .filename = filename
127120 self .line = line
128121 # unescape strings
129- if sys .version_info < (3 ,):
130- # python 2.x
131- msg = {k : escape_decode (v )[0 ] for k , v in msg .items ()}
132- else :
133- # python 3.x
134- msg = {k : escape_decode (v )[0 ]. decode (charset )
135- for k , v in msg .items ()}
122+ msg = {
123+ k : escape_decode (v )[0 ].decode (charset )
124+ for k , v in msg .items ()
125+ }
136126 # build messages as a list of tuples: (string, translation)
137127 self .messages = []
138128 if 'msgid_plural' in msg :
139129 i = 0
140130 while True :
141- key = 'msgstr[{0 }]' . format ( i )
131+ key = f 'msgstr[{ i } ]'
142132 if key not in msg :
143133 break
144134 self .messages .append ((msg ['msgid_plural' ], msg [key ]))
@@ -162,9 +152,16 @@ def check_lines(self):
162152 nb_str = count_lines (mstr )
163153 if nb_id != nb_str :
164154 errors .append (
165- PoReport ('number of lines: {0} in string, '
166- '{1} in translation' .format (nb_id , nb_str ),
167- 'lines' , self .filename , self .line , mid , mstr ))
155+ PoReport (
156+ f'number of lines: { nb_id } in string, '
157+ f'{ nb_str } in translation' ,
158+ 'lines' ,
159+ self .filename ,
160+ self .line ,
161+ mid ,
162+ mstr ,
163+ )
164+ )
168165 return errors
169166
170167 def check_punct (self , language ):
@@ -176,10 +173,15 @@ def check_punct(self, language):
176173 for mid , mstr in self .messages :
177174 if not mid or not mstr :
178175 continue
179- puncts = [(':' , ':' ), (';' , ';' ), (',' , ',' ), ('...' , '...' )]
176+ puncts = [
177+ (':' , ':' ),
178+ (';' , ';' ),
179+ (',' , ',' ),
180+ ('...' , '...' ),
181+ ]
180182 # special symbols in some languages
181183 if language [:2 ] in ['ja' , 'zh' ]:
182- puncts .append (('.' , u '。' ))
184+ puncts .append (('.' , '。' ))
183185 else :
184186 puncts .append (('.' , '.' ))
185187 for punctid , punctstr in puncts :
@@ -193,17 +195,29 @@ def check_punct(self, language):
193195 break
194196 if match_id and not match_str :
195197 errors .append (
196- PoReport (u'end punctuation: "{0}" in string, '
197- u'"{1}" not in translation'
198- '' .format (punctid , punctstr ),
199- 'punct' , self .filename , self .line , mid , mstr ))
198+ PoReport (
199+ f'end punctuation: "{ punctid } " in string, '
200+ f'"{ punctstr } " not in translation' ,
201+ 'punct' ,
202+ self .filename ,
203+ self .line ,
204+ mid ,
205+ mstr ,
206+ )
207+ )
200208 break
201209 if not match_id and match_str :
202210 errors .append (
203- PoReport (u'end punctuation: "{0}" in translation, '
204- u'"{1}" not in string'
205- '' .format (punctstr , punctid ),
206- 'punct' , self .filename , self .line , mid , mstr ))
211+ PoReport (
212+ f'end punctuation: "{ punctstr } " in '
213+ f'translation, "{ punctid } " not in string' ,
214+ 'punct' ,
215+ self .filename ,
216+ self .line ,
217+ mid ,
218+ mstr ,
219+ )
220+ )
207221 break
208222 return errors
209223
@@ -222,20 +236,31 @@ def check_whitespace(self):
222236 startout = len (mstr ) - len (mstr .lstrip (' ' ))
223237 if startin != startout :
224238 errors .append (
225- PoReport ('whitespace at beginning: {0} in string, '
226- '{1} in translation'
227- '' .format (startin , startout ),
228- 'whitespace' , self .filename , self .line , mid ,
229- mstr ))
239+ PoReport (
240+ f'whitespace at beginning: { startin } in '
241+ f'string, { startout } in translation' ,
242+ 'whitespace' ,
243+ self .filename ,
244+ self .line ,
245+ mid ,
246+ mstr ,
247+ )
248+ )
230249 # check whitespace at end of string
231250 endin = len (mid ) - len (mid .rstrip (' ' ))
232251 endout = len (mstr ) - len (mstr .rstrip (' ' ))
233252 if endin != endout :
234253 errors .append (
235- PoReport ('whitespace at end: {0} in string, '
236- '{1} in translation' .format (endin , endout ),
237- 'whitespace' , self .filename , self .line , mid ,
238- mstr ))
254+ PoReport (
255+ f'whitespace at end: { endin } in string, '
256+ f'{ endout } in translation' ,
257+ 'whitespace' ,
258+ self .filename ,
259+ self .line ,
260+ mid ,
261+ mstr ,
262+ )
263+ )
239264 return errors
240265
241266 def check_whitespace_eol (self ):
@@ -256,11 +281,16 @@ def check_whitespace_eol(self):
256281 endout = len (strlines [i ]) - len (strlines [i ].rstrip (' ' ))
257282 if (endin > 0 or endout > 0 ) and endin != endout :
258283 errors .append (
259- PoReport ('different whitespace at end of a line: {0} '
260- 'in string, {1} in translation'
261- '' .format (endin , endout ),
262- 'whitespace_eol' , self .filename , self .line ,
263- mid , mstr ))
284+ PoReport (
285+ f'different whitespace at end of a line: { endin } '
286+ f'in string, { endout } in translation' ,
287+ 'whitespace_eol' ,
288+ self .filename ,
289+ self .line ,
290+ mid ,
291+ mstr ,
292+ )
293+ )
264294 break
265295 return errors
266296
@@ -289,8 +319,16 @@ def check_spelling(self, spelling, checkers):
289319 if misspelled_word :
290320 misspelled .append (err .word )
291321 if misspelled :
292- errors .append (PoReport (misspelled , 'spelling-' + spelling ,
293- self .filename , self .line , mid , mstr ))
322+ errors .append (
323+ PoReport (
324+ misspelled ,
325+ 'spelling-' + spelling ,
326+ self .filename ,
327+ self .line ,
328+ mid ,
329+ mstr ,
330+ )
331+ )
294332 return errors
295333
296334
@@ -407,7 +445,7 @@ def read(self): # pylint: disable=too-many-locals
407445 """
408446 self .msgs = []
409447 checker = Checker ()
410- with open (self .filename , 'r' ) as po_file :
448+ with open (self .filename , 'r' , encoding = 'utf-8' ) as po_file :
411449 for line in po_file :
412450 message = checker .check_line (line .strip ())
413451 if message :
@@ -454,11 +492,8 @@ def __init__(self):
454492 self .pwl = None
455493
456494 def __repr__ (self ):
457- return ('checks: {0}, dicts: {1}, '
458- 'extra_checkers: {2}' .format (
459- self .checks ,
460- self .dicts ,
461- self .extra_checkers ))
495+ return (f'checks: { self .checks } , dicts: { self .dicts } , '
496+ f'extra_checkers: { self .extra_checkers } ' )
462497
463498 def set_check (self , check , state ):
464499 """Enable/disable a specific check."""
@@ -482,8 +517,8 @@ def set_spelling_options(self, spelling, dicts, pwl_files):
482517 _dict = Dict (lang )
483518 self .extra_checkers .append (SpellChecker (_dict ))
484519 except DictNotFoundError :
485- print ('WARNING: enchant dictionary not found for '
486- 'language "{0 }"' . format ( lang ) )
520+ print (f 'WARNING: enchant dictionary not found for '
521+ f 'language "{ lang } "' )
487522
488523 def _get_language_checker (self , po_file , reports ):
489524 """Get checker for PO file language."""
@@ -504,11 +539,14 @@ def _get_language_checker(self, po_file, reports):
504539 _dict = DictWithPWL (lang , None )
505540 checker .append (SpellChecker (_dict ))
506541 except DictNotFoundError :
507- reports .append (PoReport (
508- 'enchant dictionary not found for language "{0}"'
509- '' .format (lang ),
510- 'dict' , po_file .filename ,
511- po_file .props ['language_numline' ]))
542+ reports .append (
543+ PoReport (
544+ f'enchant dictionary not found for language "{ lang } "' ,
545+ 'dict' ,
546+ po_file .filename ,
547+ po_file .props ['language_numline' ]
548+ )
549+ )
512550 checker = []
513551 except IOError as exc :
514552 reports .append (PoReport (
@@ -586,8 +624,7 @@ def check_files(self, files):
586624 result .append ((po_file .filename , self .check_pofile (po_file )))
587625 else :
588626 # compilation failed
589- if sys .version_info >= (3 ,):
590- compile_output = bytes (compile_output ).decode ('utf-8' )
627+ compile_output = bytes (compile_output ).decode ('utf-8' )
591628 result .append ((po_file .filename ,
592629 [PoReport (compile_output , 'compile' ,
593630 po_file .filename )]))
0 commit comments