3 # Iterate through all .po files, run msgfmt for each of them, and output any
4 # errors together with their context.
6 # This script can also be used to "sanitize" .po files to avoid Ikiwiki build
7 # failures. In that case, problematic translations are removed from the .po
8 # file and replaced by an empty string. The effect is that the string in the
9 # built website will not be translated.
19 re.compile('^[^\s]+\.po:[0-9]: warning:'),
20 re.compile('^msgfmt: [^\s]+\.po: warning:'),
21 re.compile('^\s*warning:'),
24 ERRORS = re.compile('^([^\s]+\.po):([0-9]+): ')
27 def find_context_start(msgstr_line, content):
29 Find the line number of the `msgid` corresponding to the given `msgstr`.
31 start = msgstr_line - 1
32 while not content[start].startswith('msgid '):
37 def find_context_end(msgstr_line, content):
39 Find the line number corresponding to the end of the given `msgstr`.
42 while not end == len(content) and content[end] != '\n':
47 def print_error_context(file, msgstr_line):
49 Print the full msgid and msgstr surrounding the `msgstr_line` in `file`.
53 content = f.readlines()
55 start = find_context_start(msgstr_line, content)
56 end = find_context_end(msgstr_line, content)
58 for line in range(start, end):
59 print(content[line].strip())
62 def delete_msgstr(file, msgstr_line):
64 Delete the translation starting on `msgstr_line` of the file `file`.
68 content = f.readlines()
70 end = find_context_end(msgstr_line, content)
72 content[msgstr_line-1] = 'msgstr ""\n'
73 content = content[:msgstr_line] + content[end:]
75 with open(file, 'w') as f:
79 def check_po_msgfmt(sanitize=False):
81 Run `msgfmt` for all .po files in the current directory and print any
82 errors found. If `sanitize` is `True`, also delete problematic
83 translations from corresponding .po files.
88 for f in glob.glob('**/*.po', recursive=True):
89 proc = subprocess.Popen(['msgfmt', '-c', '-o', '/dev/null', f],
90 stderr=subprocess.PIPE)
91 for line in proc.stderr:
92 line = line.strip().decode('utf-8')
95 if any(map(lambda m: m.match(line), WARNINGS)):
98 # filter out non-error messages
99 match = ERRORS.match(line)
106 file, n = match.groups()
108 print_error_context(file, msgstr_line)
112 delete_msgstr(file, msgstr_line)
119 parser = argparse.ArgumentParser()
120 parser.add_argument('--sanitize', action='store_true',
121 help='Replace problematic translations with an empty string.')
122 return parser.parse_args()
125 if __name__ == '__main__':
127 check_po_msgfmt(sanitize=args.sanitize)