2 # -*- coding: utf-8 -*-
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
10 # Full author contact details are available in file CREDITS
12 # This script takes missing translations from another set of po files and
13 # merges them into the po files in this source tree.
16 import os, re, string, sys
18 from optparse import OptionParser
21 # we do unix/windows line trimming ourselves since it can happen that we
22 # are on unix, but the file has been written on windows or vice versa.
24 " Remove end of line char(s)."
25 if line[-2:-1] == '\r':
27 elif line[-1:] == '\r' or line[-1:] == '\n':
30 # file with no EOL in last line
35 " Read utf8 input file and strip lineendings."
38 line = input.readline()
42 lines.append(line.decode('UTF-8'))
47 " Extracts msgid or msgstr from lines."
50 i = lines[0].find('"')
53 msg = lines[0][i:].strip('"')
54 for i in range(1, len(lines)):
55 msg = msg + lines[i].strip('"')
59 def translate(msgid, msgstr_lines, po2):
60 msgstr = parse_msg(msgstr_lines)
63 other = po2.find(msgid)
66 if not other.translated():
69 obsolete = (msgstr_lines[0].find('#~') == 0)
70 j = msgstr_lines[0].find('"')
71 # must not assign to msgstr_lines, because that would not be seen by our caller
72 new_lines = polib.wrap(msgstr_lines[0][0:j+1] + msgstr, 76, drop_whitespace = False)
74 for i in range(0, len(new_lines)):
76 msgstr_lines.append(new_lines[i] + '"')
78 msgstr_lines.append('#~ "' + new_lines[i] + '"')
80 msgstr_lines.append('"' + new_lines[i] + '"')
84 def mergepo_polib(target, source):
86 po1 = polib.pofile(target)
87 po2 = polib.pofile(source)
88 for entry in po1.untranslated_entries():
89 other = po2.find(entry.msgid, include_obsolete_entries=True)
92 if other.translated():
93 entry.msgstr = other.msgstr
100 def mergepo_minimaldiff(target, source):
102 po2 = polib.pofile(source)
103 target_enc = polib.detect_encoding(target)
104 # for utf8 files we can use our self written parser to minimize diffs,
105 # otherwise we need to use polib
106 if target_enc != 'UTF-8':
108 po1 = open(target, 'rb')
117 for line in oldlines:
119 if line.find('"') == 0 or line.find('#~ "') == 0:
120 msgid_lines.append(line)
123 msgid = parse_msg(msgid_lines)
124 newlines.extend(msgid_lines)
127 if line.find('"') == 0 or line.find('#~ "') == 0:
128 msgstr_lines.append(line)
131 changed = changed + translate(msgid, msgstr_lines, po2)
132 newlines.extend(msgstr_lines)
135 if not in_msgid and not in_msgstr:
136 if line.find('msgid') == 0 or line.find('#~ msgid') == 0:
137 msgid_lines.append(line)
139 elif line.find('msgstr') == 0 or line.find('#~ msgstr') == 0:
140 if line.find('msgstr[') == 0 or line.find('#~ msgstr[') == 0:
141 # plural forms are not implemented
143 msgstr_lines.append(line)
146 newlines.append(line)
148 # the file ended with a msgstr
149 changed = changed + translate(msgid, msgstr_lines, po2)
150 newlines.extend(msgstr_lines)
154 # we store .po files with unix line ends in git,
155 # so do always write them even on windows
156 po1 = open(target, 'wb')
157 for line in newlines:
158 po1.write(line.encode('UTF-8') + '\n')
162 def mergepo(target, source):
163 if not os.path.exists(source):
164 sys.stderr.write('Skipping %s since %s does not exist.\n' % (target, source))
166 if not os.path.exists(target):
167 sys.stderr.write('Skipping %s since %s does not exist.\n' % (target, target))
169 sys.stderr.write('Merging %s into %s: ' % (source, target))
171 changed = mergepo_minimaldiff(target, source)
173 changed = mergepo_polib(target, source)
174 sys.stderr.write('Updated %d translations.\n' % changed)
179 parser = OptionParser(description = """This script reads translations from .po files in the given source directory
180 and adds all translations that do not already exist to the corresponding .po
181 files in the target directory. It is recommended to remerge strings from the
182 source code before running this script. Otherwise translations that are not
183 yet in the target .po files are not updated.""", usage = "Usage: %prog [options] sourcedir")
184 parser.add_option("-t", "--target", dest="target",
185 help="target directory containing .po files. If missing, it is determined from the script location.")
186 parser.add_option("-l", "--language", dest="language",
187 help="language for which translations are merged (if missing, all languages are merged)")
188 (options, args) = parser.parse_args(argv)
193 toolsdir = os.path.dirname(args[0])
195 podir1 = os.path.abspath(options.target)
197 podir1 = os.path.normpath(os.path.join(toolsdir, '../../po'))
198 podir2 = os.path.abspath(args[1])
201 name = options.language + '.po'
202 mergepo(os.path.join(podir1, name), os.path.join(podir2, name))
204 for i in os.listdir(podir1):
205 (base, ext) = os.path.splitext(i)
208 mergepo(os.path.join(podir1, i), os.path.join(podir2, i))
213 if __name__ == "__main__":