xref: /vim-8.2.3635/src/po/check.vim (revision e16b00a1)
1" Vim script for checking .po files.
2"
3" 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".
6
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
23  " remove '%', not used for formatting.
24  let idline = substitute(idline, "'%'", '', 'g')
25
26  " remove '%' used for plural forms.
27  let idline = substitute(idline, '\\nPlural-Forms: .\+;\\n', '', '')
28
29  " remove everything but % items.
30  return substitute(idline, '[^%]*\(%[-+ #''.0-9*]*l\=[dsuxXpoc%]\)\=', '\1', 'g')
31endfunc
32
33" This only works when 'wrapscan' is not set.
34let s:save_wrapscan = &wrapscan
35set nowrapscan
36
37" Start at the first "msgid" line.
38let wsv = winsaveview()
391
40/^msgid\>
41
42" When an error is detected this is set to the line number.
43" Note: this is used in the Makefile.
44let error = 0
45
46while 1
47  if getline(line('.') - 1) !~ "no-c-format"
48    " 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
66    if getline('.') !~ '^msgstr'
67      echomsg 'Missing "msgstr" in line ' . line('.')
68      if error == 0
69	let error = line('.')
70      endif
71    endif
72
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
88  endif
89
90  " Find next msgid.  Quit when there is no more.
91  let lnum = line('.')
92  silent! /^msgid\>
93  if line('.') == lnum
94    break
95  endif
96endwhile
97
98" 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
108  echomsg 'Mismatching error/warning code in line ' . line('.')
109  if error == 0
110    let error = line('.')
111  endif
112endif
113
114func! CountNl(first, last)
115  let nl = 0
116  for lnum in range(a:first, a:last)
117    let nl += count(getline(lnum), "\n")
118  endfor
119  return nl
120endfunc
121
122" Check that the \n at the end of the msgid line is also present in the msgstr
123" 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)
139    echomsg 'Mismatching "\n" in line ' . line('.')
140    if error == 0
141      let error = lnum
142    endif
143  endif
144endwhile
145
146" Check that the file is well formed according to msgfmts understanding
147if executable("msgfmt")
148  let filename = expand("%")
149  let a = system("msgfmt --statistics OLD_PO_FILE_INPUT=yes " . filename)
150  if v:shell_error != 0
151    let error = matchstr(a, filename.':\zs\d\+\ze:')+0
152    for line in split(a, '\n') | echomsg line | endfor
153  endif
154endif
155
156if error == 0
157  " If all was OK restore the view.
158  call winrestview(wsv)
159  echomsg "OK"
160else
161  exe error
162endif
163
164let &wrapscan = s:save_wrapscan
165unlet s:save_wrapscan
166
167endif
168