ChangedDlg: move buttons to the right
[TortoiseGit.git] / contrib / Utils / po-merge.cs
blob6049034a8cb44b99ed50584f4c7959d1fea9fc8c
1 /******************************************************************************
2 PO-MERGE - A simple po merge/update tool
4 Copyright (C) 2006 - Dongsheng Song <dongsheng.song@gmail.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
20 Description:
21 This program will replace the translation in old.po file with update.po file,
22 write the result to new.po file. Only msgstr in old.po file be modified, msgid
23 become unwound. Strings(msgstr) that are not found in the update.po are left
24 untouched.
26 The two input file(update.po & old.po) must use UTF-8 enconding, the output
27 file(new.po) enconding is UTF-8 too, without any byte-order-mark (BOM).
29 Use:
30 po-merge update.po old.po new.po
32 ******************************************************************************/
34 using System;
35 using System.Collections;
36 using System.IO;
37 using System.Text;
39 class Program
41 private static void Usage() {
42 Console.WriteLine("Usage:\n\tpo-merge update.po old.po new.po\n" +
43 "\n" +
44 "This program will replace the translation in old.po file with " +
45 "update.po file, write the result to new.po file.\n\n" +
46 "Only msgstr in old.po file be modified, all msgid/msgstr become unwound. " +
47 "Strings(msgstr) that are not found in the update.po are left untouched.\n"
51 public static void Main(String[] args) {
52 if (args.Length != 3) {
53 Usage();
54 return;
57 Hashtable msg = ParseTranslation(args[0]);
59 UpdateTranslation(args[1], args[2], msg);
63 Read translation entry from the file and return a Hashtable
64 with the msgid and msgstr.The msgid and msgstr are strings.
66 private static Hashtable ParseTranslation(String filename) {
67 Hashtable msg = new Hashtable(2047);
68 StreamReader sr = new StreamReader(filename, Encoding.UTF8);
69 int n = 0;
70 bool isFinished = false;
71 String line, msgid, msgstr;
73 while (true) {
74 while (true) {
75 n++;
76 line = sr.ReadLine();
77 if (line == null) {
78 isFinished = true;
79 break;
82 // May be non-empty msgid ?
83 line = line.Trim();
85 if (line.Length >= 8 && line[0] != '#')
86 break;
89 if (isFinished)
90 break;
92 if (!line.StartsWith("msgid \"") || (line[line.Length - 1] != '\"')) {
93 Console.Error.WriteLine("parse error before msgid, file {0}, line {1:d}:\n\t", filename, n);
94 throw new Exception("parse error");
97 // Get msgid
98 if (line.Length <= 8) {
99 msgid = "";
100 } else {
101 msgid = line.Substring(7, line.Length - 8);
104 while (true) {
105 n++;
106 line = sr.ReadLine();
107 if (line == null) {
108 Console.Error.WriteLine("parse msgid error, file {0}, line {1:d}:\n\t", filename, n);
109 throw new Exception("parse error");
112 line = line.Trim();
113 if (line.Length == 0 || line[0] != '"')
114 break;
116 msgid += line.Substring(1, line.Length - 2);
119 if (!line.StartsWith("msgstr \"") || (line[line.Length - 1] != '\"')) {
120 Console.Error.WriteLine("parse error after msgid, file {0}, line {1:d}:\n\t", filename, n);
121 throw new Exception("parse error");
124 // Get msgstr
125 if (line.Length <= 9) {
126 msgstr = "";
127 } else {
128 msgstr = line.Substring(8, line.Length - 9);
131 while (true) {
132 n++;
133 line = sr.ReadLine();
134 if (line == null) break;
136 line = line.Trim();
137 if (line.Length == 0 || line[0] != '"')
138 break;
140 if (msgid.Length == 0)
141 msgstr += "\"\n\"";
143 msgstr += line.Substring(1, line.Length - 2);
146 msg[msgid] = msgstr;
148 // Console.WriteLine("msgid: [{0}]\nmsgstr: [{1}]\n", msgid, msgstr);
150 if (line == null)
151 break;
153 if (line.Length != 0 && line[0] != '#') {
154 Console.Error.WriteLine("parse error after msgstr, file {0}, line {1:d}:\n\t", filename, n);
155 throw new Exception("parse error");
159 sr.Close();
161 return msg;
165 Read translation entry from the file and update the msgid and msgstr, write to new file.
167 private static void UpdateTranslation(String filename, String newfilename, Hashtable msg) {
168 StreamReader sr = new StreamReader(filename, Encoding.UTF8);
169 StreamWriter sw = new StreamWriter(newfilename, false);
171 int n = 0, total = 0, tr = 0, ut = 0, mt = 0;
172 bool isFinished = false;
173 String line, msgid, msgstr, str = "";
175 while (true) {
176 while (true) {
177 n++;
178 line = sr.ReadLine();
179 if (line == null) {
180 isFinished = true;
181 break;
184 str = line.Trim();
186 // May be non-empty msgid ?
187 if (str.Length >= 8 && str[0] != '#')
188 break;
190 if (total == 0 && str.Equals("#, fuzzy"))
191 line = ""; // Remove PO file header fuzzy
193 sw.WriteLine(line);
196 if (isFinished) break;
198 if (!str.StartsWith("msgid \"") || (str[str.Length - 1] != '\"')) {
199 Console.Error.WriteLine("parse error before msgid, file {0}, line {1:d}:\n\t", filename, n);
200 throw new Exception("parse error");
203 // Get msgid
204 if (str.Length <= 8) {
205 msgid = "";
206 } else {
207 msgid = str.Substring(7, str.Length - 8);
210 while (true) {
211 n++;
212 line = sr.ReadLine();
213 if (line == null)
215 Console.Error.WriteLine("parse msgid error, file {0}, line {1:d}:\n\t", filename, n);
216 throw new Exception("parse error");
219 str = line.Trim();
221 if (str.Length == 0 || line[0] != '"')
222 break;
224 msgid += str.Substring(1, str.Length - 2);
227 if (!str.StartsWith("msgstr \"") || (str[str.Length - 1] != '\"')) {
228 Console.Error.WriteLine("parse error after msgid, file {0}, line {1:d}:\n\t", filename, n);
229 throw new Exception("parse error");
232 // Get msgstr
233 if (str.Length <= 9) {
234 msgstr = "";
235 } else {
236 msgstr = str.Substring(8, str.Length - 9);
239 while (true) {
240 n++;
241 line = sr.ReadLine();
242 if (line == null)
243 break;
245 str = line.Trim();
247 if (str.Length == 0 || str[0] != '"')
248 break;
250 if (msgid.Length == 0)
251 msgstr += "\"\n\"";
253 msgstr += str.Substring(1, str.Length - 2);
256 if (msgid.Length > 0)
257 total++;
259 str = (String) msg[msgid];
261 // Console.WriteLine("msgid: [{0}]\nmsgstr: [{1}]\nupdate: [{2}]\n", msgid, msgstr, str);
262 if (msgid.Length <= 0) {
263 sw.WriteLine("msgid \"{0}\"", msgid);
264 sw.WriteLine("msgstr \"{0}\"\n", msgstr);
265 } else if (str != null && str.Length > 0) {
266 if (msgid.Length != 0) {
267 if (! msgstr.Equals(str)) mt ++;
268 tr ++;
270 sw.WriteLine("msgid \"{0}\"", msgid);
271 sw.WriteLine("msgstr \"{0}\"\n", str);
272 } else {
273 if (msgstr.Length == 0) {
274 ut ++;
275 } else {
276 tr++;
278 sw.WriteLine("msgid \"{0}\"", msgid);
279 sw.WriteLine("msgstr \"{0}\"\n", msgstr);
282 if (line == null) {
283 break;
286 if (line.Length != 0 && line[0] != '#') {
287 Console.Error.WriteLine("parse error after msgstr, file {0}, line {1:d}:\n\t", filename, n);
288 throw new Exception("parse error");
292 Console.Error.WriteLine("Total {0} messages, {1} translated, {2} updated, {3} untranslated.",
293 total, tr, mt, ut);
295 sr.Close();
296 sw.Close();
298 return;