Follow-up to r29036: Now that the "mergeinfo" transaction file is no
[svn.git] / tools / dev / po-merge.py
blob97ad01cab77b631f5ede0f906beacfa599a2153c
1 #!/usr/bin/env python
3 import os, sys
5 def parse_translation(f):
6 """Read a single translation entry from the file F and return a
7 tuple with the comments, msgid and msgstr. The comments is returned
8 as a list of lines which do not end in new-lines. The msgid and
9 msgstr are strings, possibly with embedded newlines"""
10 line = f.readline()
12 # Parse comments
13 comments = []
14 while 1:
15 if line.strip() == '':
16 return comments, None, None
17 elif line[0] == '#':
18 comments.append(line[:-1])
19 else:
20 break
21 line = f.readline()
23 # Parse msgid
24 if line[:7] != 'msgid "' or line[-2] != '"':
25 raise RuntimeError("parse error")
26 msgid = line[6:-1]
27 while 1:
28 line = f.readline()
29 if line[0] != '"':
30 break
31 msgid += '\n' + line[:-1]
33 # Parse msgstr
34 if line[:8] != 'msgstr "' or line[-2] != '"':
35 raise RuntimeError("parse error")
36 msgstr = line[7:-1]
37 while 1:
38 line = f.readline()
39 if len(line) == 0 or line[0] != '"':
40 break
41 msgstr += '\n' + line[:-1]
43 if line.strip() != '':
44 raise RuntimeError("parse error")
46 return comments, msgid, msgstr
48 def split_comments(comments):
49 """Split COMMENTS into flag comments and other comments. Flag
50 comments are those that begin with '#,', e.g. '#,fuzzy'."""
51 flags = []
52 other = []
53 for c in comments:
54 if len(c) > 1 and c[1] == ',':
55 flags.append(c)
56 else:
57 other.append(c)
58 return flags, other
60 def main(argv):
61 if len(argv) != 2:
62 argv0 = os.path.basename(argv[0])
63 sys.exit('Usage: %s <lang.po>\n'
64 '\n'
65 'This script will replace the translations and flags in lang.po with\n'
66 'the translations and flags in the source po file read from standard\n'
67 'input. Strings that are not found in the source file are left untouched.\n'
68 'A backup copy of lang.po is saved as lang.po.bak.\n'
69 '\n'
70 'Example:\n'
71 ' svn cat http://svn.collab.net/repos/svn/trunk/subversion/po/sv.po | \\\n'
72 ' %s sv.po' % (argv0, argv0))
74 # Read the source po file into a hash
75 source = {}
76 while 1:
77 comments, msgid, msgstr = parse_translation(sys.stdin)
78 if not comments and msgid is None:
79 break
80 if msgid is not None:
81 source[msgid] = msgstr, split_comments(comments)[0]
83 # Make a backup of the output file, open the copy for reading
84 # and the original for writing.
85 os.rename(argv[1], argv[1] + '.bak')
86 infile = open(argv[1] + '.bak')
87 outfile = open(argv[1], 'w')
89 # Loop thought the original and replace stuff as we go
90 first = 1
91 string_count = 0
92 update_count = 0
93 untranslated = 0
94 while 1:
95 comments, msgid, msgstr = parse_translation(infile)
96 if not comments and msgid is None:
97 break
98 if not first:
99 outfile.write('\n')
100 first = 0
101 if msgid is None:
102 outfile.write('\n'.join(comments) + '\n')
103 else:
104 string_count += 1
105 # Do not update the header, and only update if the source
106 # has a non-empty translation.
107 if msgid != '""' and source.get(msgid, ['""', []])[0] != '""':
108 other = split_comments(comments)[1]
109 new_msgstr, new_flags = source[msgid]
110 new_comments = other + new_flags
111 if new_msgstr != msgstr or new_comments != comments:
112 update_count += 1
113 msgstr = new_msgstr
114 comments = new_comments
115 outfile.write('\n'.join(comments) + '\n')
116 outfile.write('msgid ' + msgid + '\n')
117 outfile.write('msgstr ' + msgstr + '\n')
118 if msgstr == '""':
119 untranslated += 1
121 # We're done. Tell the user what we did.
122 print('%d strings updated. '
123 '%d of %d strings are still untranslated (%.0f%%).' %
124 (update_count, untranslated, string_count,
125 100.0 * untranslated / string_count))
127 if __name__ == '__main__':
128 main(sys.argv)