blob: a1ec6237e77bb8d2bfcaa5d72fefa4304e5c59ef [file] [log] [blame]
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00001" Vim script for checking .po files.
2"
Bram Moolenaar595f51c2008-06-09 12:46:00 +00003" Go through the file and verify that:
4" - All %...s items in "msgid" are identical to the ones in "msgstr".
5" - An error or warning code in "msgid" matches the one in "msgstr".
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00006
7if 1 " Only execute this if the eval feature is available.
8
9" Function to get a split line at the cursor.
10" Used for both msgid and msgstr lines.
11" Removes all text except % items and returns the result.
12func! GetMline()
13 let idline = substitute(getline('.'), '"\(.*\)"$', '\1', '')
14 while line('.') < line('$')
15 +
16 let line = getline('.')
17 if line[0] != '"'
18 break
19 endif
20 let idline .= substitute(line, '"\(.*\)"$', '\1', '')
21 endwhile
22
Bram Moolenaara5792f52005-11-23 21:25:05 +000023 " remove '%', not used for formatting.
24 let idline = substitute(idline, "'%'", '', 'g')
25
Bram Moolenaar1c6136a2009-09-11 11:00:05 +000026 " remove '%' used for plural forms.
27 let idline = substitute(idline, '\\nPlural-Forms: .\+;\\n', '', '')
28
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000029 " remove everything but % items.
30 return substitute(idline, '[^%]*\(%[-+ #''.0-9*]*l\=[dsuxXpoc%]\)\=', '\1', 'g')
31endfunc
32
Bram Moolenaarec420592016-08-26 15:51:53 +020033" This only works when 'wrapscan' is not set.
Bram Moolenaara411e5d2010-08-04 15:47:08 +020034let s:save_wrapscan = &wrapscan
Bram Moolenaarec420592016-08-26 15:51:53 +020035set nowrapscan
Bram Moolenaara411e5d2010-08-04 15:47:08 +020036
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000037" Start at the first "msgid" line.
Bram Moolenaar7f937032017-07-19 14:34:42 +020038let wsv = winsaveview()
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +0000391
Bram Moolenaarec420592016-08-26 15:51:53 +020040/^msgid\>
41
42" When an error is detected this is set to the line number.
43" Note: this is used in the Makefile.
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000044let error = 0
45
46while 1
47 if getline(line('.') - 1) !~ "no-c-format"
Bram Moolenaarec420592016-08-26 15:51:53 +020048 " go over the "msgid" and "msgid_plural" lines
49 let prevfromline = 'foobar'
50 while 1
51 let fromline = GetMline()
52 if prevfromline != 'foobar' && prevfromline != fromline
53 echomsg 'Mismatching % in line ' . (line('.') - 1)
54 echomsg 'msgid: ' . prevfromline
55 echomsg 'msgid ' . fromline
56 if error == 0
57 let error = line('.')
58 endif
59 endif
60 if getline('.') !~ 'msgid_plural'
61 break
62 endif
63 let prevfromline = fromline
64 endwhile
65
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000066 if getline('.') !~ '^msgstr'
Bram Moolenaarec420592016-08-26 15:51:53 +020067 echomsg 'Missing "msgstr" in line ' . line('.')
68 if error == 0
69 let error = line('.')
70 endif
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000071 endif
Bram Moolenaarec420592016-08-26 15:51:53 +020072
73 " check all the 'msgstr' lines
74 while getline('.') =~ '^msgstr'
75 let toline = GetMline()
76 if fromline != toline
77 echomsg 'Mismatching % in line ' . (line('.') - 1)
78 echomsg 'msgid: ' . fromline
79 echomsg 'msgstr: ' . toline
80 if error == 0
81 let error = line('.')
82 endif
83 endif
84 if line('.') == line('$')
85 break
86 endif
87 endwhile
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000088 endif
89
Bram Moolenaarec420592016-08-26 15:51:53 +020090 " Find next msgid. Quit when there is no more.
91 let lnum = line('.')
92 silent! /^msgid\>
93 if line('.') == lnum
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +000094 break
95 endif
96endwhile
97
Bram Moolenaar595f51c2008-06-09 12:46:00 +000098" Check that error code in msgid matches the one in msgstr.
99"
100" Examples of mismatches found with msgid "E123: ..."
101" - msgstr "E321: ..." error code mismatch
102" - msgstr "W123: ..." warning instead of error
103" - msgstr "E123 ..." missing colon
104" - msgstr "..." missing error code
105"
1061
107if search('msgid "\("\n"\)\?\([EW][0-9]\+:\).*\nmsgstr "\("\n"\)\?[^"]\@=\2\@!') > 0
Bram Moolenaarec420592016-08-26 15:51:53 +0200108 echomsg 'Mismatching error/warning code in line ' . line('.')
109 if error == 0
110 let error = line('.')
111 endif
Bram Moolenaar595f51c2008-06-09 12:46:00 +0000112endif
113
Bram Moolenaar7f937032017-07-19 14:34:42 +0200114func! CountNl(first, last)
115 let nl = 0
116 for lnum in range(a:first, a:last)
Bram Moolenaar9966b212017-07-28 16:46:57 +0200117 let nl += count(getline(lnum), "\n")
Bram Moolenaar7f937032017-07-19 14:34:42 +0200118 endfor
119 return nl
120endfunc
121
Bram Moolenaar9966b212017-07-28 16:46:57 +0200122" Check that the \n at the end of the msgid line is also present in the msgstr
Bram Moolenaar7f937032017-07-19 14:34:42 +0200123" line. Skip over the header.
124/^"MIME-Version:
125while 1
126 let lnum = search('^msgid\>')
127 if lnum <= 0
128 break
129 endif
130 let strlnum = search('^msgstr\>')
131 let end = search('^$')
132 if end <= 0
133 let end = line('$') + 1
134 endif
135 let origcount = CountNl(lnum, strlnum - 1)
136 let transcount = CountNl(strlnum, end - 1)
137 " Allow for a few more or less line breaks when there are 2 or more
138 if origcount != transcount && (origcount <= 2 || transcount <= 2)
Bram Moolenaar9966b212017-07-28 16:46:57 +0200139 echomsg 'Mismatching "\n" in line ' . line('.')
Bram Moolenaar7f937032017-07-19 14:34:42 +0200140 if error == 0
141 let error = lnum
142 endif
143 endif
144endwhile
145
Bram Moolenaaraaef1ba2017-08-01 17:40:23 +0200146" Check that the file is well formed according to msgfmts understanding
147if executable("msgfmt")
148 let filename = expand("%")
Bram Moolenaar01164a62017-11-02 22:58:42 +0100149 " Newer msgfmt does not take OLD_PO_FILE_INPUT argument, must be in
150 " environment.
151 let $OLD_PO_FILE_INPUT = 'yes'
152 let a = system("msgfmt --statistics " . filename)
Bram Moolenaaraaef1ba2017-08-01 17:40:23 +0200153 if v:shell_error != 0
154 let error = matchstr(a, filename.':\zs\d\+\ze:')+0
155 for line in split(a, '\n') | echomsg line | endfor
156 endif
157endif
158
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +0000159if error == 0
Bram Moolenaar7f937032017-07-19 14:34:42 +0200160 " If all was OK restore the view.
161 call winrestview(wsv)
Bram Moolenaarec420592016-08-26 15:51:53 +0200162 echomsg "OK"
163else
164 exe error
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +0000165endif
166
Bram Moolenaara411e5d2010-08-04 15:47:08 +0200167let &wrapscan = s:save_wrapscan
168unlet s:save_wrapscan
169
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +0000170endif