13
13
__version__ = "0.6.6"
14
14
15
15
import argparse
16
+ import io
16
17
import multiprocessing
17
18
import os
18
19
import sys
21
22
from itertools import chain , starmap
22
23
from os .path import exists , isfile , join , splitext
23
24
25
+ from polib import pofile , POFile
24
26
import regex as re
25
27
26
-
27
28
# The following chars groups are from docutils:
28
29
CLOSING_DELIMITERS = "\\ \\ .,;!?"
29
30
DELIMITERS = (
@@ -193,7 +194,7 @@ def check_python_syntax(file, lines, options=None):
193
194
role_missing_closing_backtick = re .compile (rf"({ ROLE_HEAD } `[^`]+?)[^`]*$" )
194
195
195
196
196
- @checker (".rst" )
197
+ @checker (".rst" , ".po" )
197
198
def check_missing_backtick_after_role (file , lines , options = None ):
198
199
"""Search for roles missing their closing backticks.
199
200
@@ -246,7 +247,7 @@ def clean_paragraph(paragraph):
246
247
return paragraph .replace ("\x00 " , "\\ " )
247
248
248
249
249
- @checker (".rst" )
250
+ @checker (".rst" , ".po" )
250
251
def check_missing_space_after_literal (file , lines , options = None ):
251
252
r"""Search for inline literals immediately followed by a character.
252
253
@@ -267,7 +268,7 @@ def check_missing_space_after_literal(file, lines, options=None):
267
268
)
268
269
269
270
270
- @checker (".rst" )
271
+ @checker (".rst" , ".po" )
271
272
def check_unbalanced_inline_literals_delimiters (file , lines , options = None ):
272
273
r"""Search for unbalanced inline literals delimiters.
273
274
@@ -445,7 +446,7 @@ def inline_markup_gen(start_string, end_string, extra_allowed_before=""):
445
446
)
446
447
447
448
448
- @checker (".rst" , enabled = False )
449
+ @checker (".rst" , ".po" , enabled = False )
449
450
def check_default_role (file , lines , options = None ):
450
451
"""Search for default roles (but they are allowed in many projects).
451
452
@@ -471,7 +472,7 @@ def check_default_role(file, lines, options=None):
471
472
yield lno , "default role used (hint: for inline literals, use double backticks)"
472
473
473
474
474
- @checker (".rst" )
475
+ @checker (".rst" , ".po" )
475
476
def check_directive_with_three_dots (file , lines , options = None ):
476
477
"""Search for directives with three dots instead of two.
477
478
@@ -483,7 +484,7 @@ def check_directive_with_three_dots(file, lines, options=None):
483
484
yield lno , "directive should start with two dots, not three."
484
485
485
486
486
- @checker (".rst" )
487
+ @checker (".rst" , ".po" )
487
488
def check_directive_missing_colons (file , lines , options = None ):
488
489
"""Search for directive wrongly typed as comments.
489
490
@@ -495,7 +496,7 @@ def check_directive_missing_colons(file, lines, options=None):
495
496
yield lno , "comment seems to be intended as a directive"
496
497
497
498
498
- @checker (".rst" )
499
+ @checker (".rst" , ".po" )
499
500
def check_missing_space_after_role (file , lines , options = None ):
500
501
r"""Search for roles immediately followed by a character.
501
502
@@ -515,7 +516,7 @@ def check_missing_space_after_role(file, lines, options=None):
515
516
yield lno , f"role missing (escaped) space after role: { role .group (0 )!r} "
516
517
517
518
518
- @checker (".rst" )
519
+ @checker (".rst" , ".po" )
519
520
def check_role_without_backticks (file , lines , options = None ):
520
521
"""Search roles without backticks.
521
522
@@ -528,7 +529,7 @@ def check_role_without_backticks(file, lines, options=None):
528
529
yield lno , f"role with no backticks: { no_backticks .group (0 )!r} "
529
530
530
531
531
- @checker (".rst" )
532
+ @checker (".rst" , ".po" )
532
533
def check_backtick_before_role (file , lines , options = None ):
533
534
"""Search for roles preceded by a backtick.
534
535
@@ -542,7 +543,7 @@ def check_backtick_before_role(file, lines, options=None):
542
543
yield lno , "superfluous backtick in front of role"
543
544
544
545
545
- @checker (".rst" )
546
+ @checker (".rst" , ".po" )
546
547
def check_missing_space_in_hyperlink (file , lines , options = None ):
547
548
"""Search for hyperlinks missing a space.
548
549
@@ -557,7 +558,7 @@ def check_missing_space_in_hyperlink(file, lines, options=None):
557
558
yield lno , "missing space before < in hyperlink"
558
559
559
560
560
- @checker (".rst" )
561
+ @checker (".rst" , ".po" )
561
562
def check_missing_underscore_after_hyperlink (file , lines , options = None ):
562
563
"""Search for hyperlinks missing underscore after their closing backtick.
563
564
@@ -572,7 +573,7 @@ def check_missing_underscore_after_hyperlink(file, lines, options=None):
572
573
yield lno , "missing underscore after closing backtick in hyperlink"
573
574
574
575
575
- @checker (".rst" )
576
+ @checker (".rst" , ".po" )
576
577
def check_role_with_double_backticks (file , lines , options = None ):
577
578
"""Search for roles with double backticks.
578
579
@@ -638,7 +639,7 @@ def looks_like_glued(match):
638
639
return True
639
640
640
641
641
- @checker (".rst" )
642
+ @checker (".rst" , ".po" )
642
643
def check_missing_space_before_role (file , lines , options = None ):
643
644
"""Search for missing spaces before roles.
644
645
@@ -658,7 +659,7 @@ def check_missing_space_before_role(file, lines, options=None):
658
659
yield paragraph_lno + error_offset , f"role missing opening tag colon ({ match .group (0 )} )."
659
660
660
661
661
- @checker (".rst" )
662
+ @checker (".rst" , ".po" )
662
663
def check_missing_space_before_default_role (file , lines , options = None ):
663
664
"""Search for missing spaces before default role.
664
665
@@ -681,7 +682,7 @@ def check_missing_space_before_default_role(file, lines, options=None):
681
682
)
682
683
683
684
684
- @checker (".rst" )
685
+ @checker (".rst" , ".po" )
685
686
def check_hyperlink_reference_missing_backtick (file , lines , options = None ):
686
687
"""Search for missing backticks in front of hyperlink references.
687
688
@@ -702,7 +703,7 @@ def check_hyperlink_reference_missing_backtick(file, lines, options=None):
702
703
)
703
704
704
705
705
- @checker (".rst" )
706
+ @checker (".rst" , ".po" )
706
707
def check_missing_colon_in_role (file , lines , options = None ):
707
708
"""Search for missing colons in roles.
708
709
@@ -715,23 +716,23 @@ def check_missing_colon_in_role(file, lines, options=None):
715
716
yield lno , f"role missing colon before first backtick ({ match .group (0 )} )."
716
717
717
718
718
- @checker (".py" , ".rst" , rst_only = False )
719
+ @checker (".py" , ".rst" , ".po" , rst_only = False )
719
720
def check_carriage_return (file , lines , options = None ):
720
721
r"""Check for carriage returns (\r) in lines."""
721
722
for lno , line in enumerate (lines ):
722
723
if "\r " in line :
723
724
yield lno + 1 , "\\ r in line"
724
725
725
726
726
- @checker (".py" , ".rst" , rst_only = False )
727
+ @checker (".py" , ".rst" , ".po" , rst_only = False )
727
728
def check_horizontal_tab (file , lines , options = None ):
728
729
r"""Check for horizontal tabs (\t) in lines."""
729
730
for lno , line in en
10000
umerate (lines ):
730
731
if "\t " in line :
731
732
yield lno + 1 , "OMG TABS!!!1"
732
733
733
734
734
- @checker (".py" , ".rst" , rst_only = False )
735
+ @checker (".py" , ".rst" , ".po" , rst_only = False )
735
736
def check_trailing_whitespace (file , lines , options = None ):
736
737
"""Check for trailing whitespaces at end of lines."""
737
738
for lno , line in enumerate (lines ):
@@ -740,14 +741,14 @@ def check_trailing_whitespace(file, lines, options=None):
740
741
yield lno + 1 , "trailing whitespace"
741
742
742
743
743
- @checker (".py" , ".rst" , rst_only = False )
744
+ @checker (".py" , ".rst" , ".po" , rst_only = False )
744
745
def check_missing_final_newline (file , lines , options = None ):
745
746
"""Check that the last line of the file ends with a newline."""
746
747
if lines and not lines [- 1 ].endswith ("\n " ):
747
748
yield len (lines ), "No newline at end of file."
748
749
749
750
750
- @checker (".rst" , enabled = False , rst_only = True )
751
+ @checker (".rst" , ".po" , enabled = False , rst_only = True )
751
752
def check_line_too_long (file , lines , options = None ):
752
753
"""Check for line length; this checker is not run by default."""
753
754
for lno , line in enumerate (lines ):
@@ -849,7 +850,7 @@ def type_of_explicit_markup(line):
849
850
)
850
851
851
852
852
- @checker (".rst" , enabled = False )
853
+ @checker (".rst" , ".po" , enabled = False )
853
854
def check_triple_backticks (file , lines , options = None ):
854
855
"""Check for triple backticks, like ```Point``` (but it's a valid syntax).
855
856
@@ -866,7 +867,7 @@ def check_triple_backticks(file, lines, options=None):
866
867
yield lno + 1 , "There's no rst syntax using triple backticks"
867
868
868
869
869
- @checker (".rst" , rst_only = False )
870
+ @checker (".rst" , ".po" , rst_only = False )
870
871
def check_bad_dedent (file , lines , options = None ):
871
872
"""Check for mis-alignment in indentation in code blocks.
872
873
@@ -1023,13 +1024,28 @@ def check_text(filename, text, checkers, options=None):
1023
1024
return errors
1024
1025
1025
1026
1027
+ def po2rst (text ):
1028
+ """Extract msgstr entries from a po content, keeping linenos."""
1029
+ output = []
1030
+ po = pofile (text , encoding = "UTF-8" )
1031
+ for entry in po .translated_entries ():
1032
+ # Don't check original msgid, assume it's checked directly.
1033
+ while len (output ) + 1 < entry .linenum :
1034
+ output .append ("\n " )
1035
+ for line in entry .msgstr .splitlines ():
1036
+ output .append (line + "\n " )
1037
+ return "" .join (output )
1038
+
1039
+
1026
1040
def check_file (filename , checkers , options : CheckersOptions = None ):
1027
1041
ext = splitext (filename )[1 ]
1028
1042
if not any (ext in checker .suffixes for checker in checkers ):
1029
1043
return Counter ()
1030
1044
try :
1031
1045
with open (filename , encoding = "utf-8" ) as f :
1032
1046
text = f .read ()
1047
+ if filename .endswith (".po" ):
1048
+ text = po2rst (text )
1033
1049
except OSError as err :
1034
1050
print (f"{ filename } : cannot open: { err } " )
1035
1051
return Counter ({4 : 1 })
0 commit comments