Fixed issue 923: Code spelling fix: function ReadTreeRecurive should be ReadTreeRecursive
[TortoiseGit.git] / src / ResText / POFile.cpp
blobb4e8cac454c33bbaf56d51a0b00e8ef733728ae4
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 #include "StdAfx.h"
19 #include "shlwapi.h"
20 #include <fstream>
21 #include "codecvt.h"
22 #include "Utils.h"
23 #include "ResModule.h"
24 #include ".\pofile.h"
26 #define MYERROR {CUtils::Error(); return FALSE;}
28 CPOFile::CPOFile()
32 CPOFile::~CPOFile(void)
36 BOOL CPOFile::ParseFile(LPCTSTR szPath, BOOL bUpdateExisting /* = TRUE */)
38 if (!PathFileExists(szPath))
39 return FALSE;
41 if (!m_bQuiet)
42 _ftprintf(stdout, _T("parsing file %s...\n"), szPath);
44 int nEntries = 0;
45 int nDeleted = 0;
46 int nTranslated = 0;
47 //since stream classes still expect the filepath in char and not wchar_t
48 //we need to convert the filepath to multibyte
49 char filepath[MAX_PATH+1];
50 SecureZeroMemory(filepath, sizeof(filepath));
51 WideCharToMultiByte(CP_ACP, NULL, szPath, -1, filepath, MAX_PATH, NULL, NULL);
53 std::wifstream File;
54 File.imbue(std::locale(std::locale(), new utf8_conversion()));
55 File.open(filepath);
56 if (!File.good())
58 _ftprintf(stderr, _T("can't open input file %s\n"), szPath);
59 return FALSE;
61 TCHAR line[2*MAX_STRING_LENGTH];
62 std::vector<std::wstring> entry;
65 File.getline(line, _countof(line));
66 if (line[0]==0)
68 //empty line means end of entry!
69 RESOURCEENTRY resEntry;
70 std::wstring msgid;
71 int type = 0;
72 for (std::vector<std::wstring>::iterator I = entry.begin(); I != entry.end(); ++I)
74 if (_tcsncmp(I->c_str(), _T("# "), 2)==0)
76 //user comment
77 resEntry.translatorcomments.push_back(I->c_str());
78 type = 0;
80 if (_tcsncmp(I->c_str(), _T("#."), 2)==0)
82 //automatic comments
83 resEntry.automaticcomments.push_back(I->c_str());
84 type = 0;
86 if (_tcsncmp(I->c_str(), _T("#,"), 2)==0)
88 //flag
89 resEntry.flag = I->c_str();
90 type = 0;
92 if (_tcsncmp(I->c_str(), _T("msgid"), 5)==0)
94 //message id
95 msgid = I->c_str();
96 msgid = std::wstring(msgid.substr(7, msgid.size() - 8));
97 nEntries++;
98 type = 1;
100 if (_tcsncmp(I->c_str(), _T("msgstr"), 6)==0)
102 //message string
103 resEntry.msgstr = I->c_str();
104 resEntry.msgstr = resEntry.msgstr.substr(8, resEntry.msgstr.length() - 9);
105 if (resEntry.msgstr.size()>0)
106 nTranslated++;
107 type = 2;
109 if (_tcsncmp(I->c_str(), _T("\""), 1)==0)
111 if (type == 1)
113 std::wstring temp = I->c_str();
114 temp = temp.substr(1, temp.length()-2);
115 msgid += temp;
117 if (type == 2)
119 if (resEntry.msgstr.size() == 0)
120 nTranslated++;
121 std::wstring temp = I->c_str();
122 temp = temp.substr(1, temp.length()-2);
123 resEntry.msgstr += temp;
127 entry.clear();
128 if ((bUpdateExisting)&&(this->count(msgid) == 0))
129 nDeleted++;
130 else
131 (*this)[msgid] = resEntry;
132 msgid.clear();
134 else
136 entry.push_back(line);
138 } while (File.gcount() > 0);
139 printf(File.getloc().name().c_str());
140 File.close();
141 RESOURCEENTRY emptyentry;
142 (*this)[std::wstring(_T(""))] = emptyentry;
143 if (!m_bQuiet)
144 _ftprintf(stdout, _T("%d Entries found, %d were already translated and %d got deleted\n"), nEntries, nTranslated, nDeleted);
145 return TRUE;
148 BOOL CPOFile::SaveFile(LPCTSTR szPath)
150 //since stream classes still expect the filepath in char and not wchar_t
151 //we need to convert the filepath to multibyte
152 char filepath[MAX_PATH+1];
153 int nEntries = 0;
154 SecureZeroMemory(filepath, sizeof(filepath));
155 WideCharToMultiByte(CP_ACP, NULL, szPath, -1, filepath, MAX_PATH, NULL, NULL);
157 std::wofstream File;
158 // File.open(filepath, std::ios_base::binary);
159 // File << _T("\xEF\xBB\xBF");
160 // File.close();
161 File.imbue(std::locale(std::locale(), new utf8_conversion()));
162 File.open(filepath, std::ios_base::binary);
163 File << _T("# SOME DESCRIPTIVE TITLE.\n");
164 File << _T("# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n");
165 File << _T("# This file is distributed under the same license as the PACKAGE package.\n");
166 File << _T("# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n");
167 File << _T("#\n");
168 File << _T("#, fuzzy\n");
169 File << _T("msgid \"\"\n");
170 File << _T("msgstr \"\"\n");
171 File << _T("\"Project-Id-Version: PACKAGE VERSION\\n\"\n");
172 File << _T("\"Report-Msgid-Bugs-To: \\n\"\n");
173 File << _T("\"POT-Creation-Date: 1900-01-01 00:00+0000\\n\"\n");
174 File << _T("\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n");
175 File << _T("\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n");
176 File << _T("\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n");
177 File << _T("\"MIME-Version: 1.0\\n\"\n");
178 File << _T("\"Content-Type: text/plain; charset=UTF-8\\n\"\n");
179 File << _T("\"Content-Transfer-Encoding: 8bit\\n\"\n\n");
180 File << _T("\n");
181 File << _T("# msgid/msgstr fields for Accelerator keys\n");
182 File << _T("# Format is: \"ID:xxxxxx:VACS+X\" where:\n");
183 File << _T("# ID:xxxxx = the menu ID corresponding to the accelerator\n");
184 File << _T("# V = Virtual key (or blank if not used) - nearly always set!\n");
185 File << _T("# A = Alt key (or blank if not used)\n");
186 File << _T("# C = Ctrl key (or blank if not used)\n");
187 File << _T("# S = Shift key (or blank if not used)\n");
188 File << _T("# X = upper case character\n");
189 File << _T("# e.g. \"V CS+Q\" == Ctrl + Shift + 'Q'\n");
190 File << _T("\n");
191 File << _T("# ONLY Accelerator Keys with corresponding alphanumeric characters can be\n");
192 File << _T("# updated i.e. function keys (F2), special keys (Delete, HoMe) etc. will not.\n");
193 File << _T("\n");
194 File << _T("# ONLY change the msgstr field. Do NOT change any other.\n");
195 File << _T("# If you do not want to change an Accelerator Key, copy msgid to msgstr\n");
196 File << _T("\n");
198 for (std::map<std::wstring, RESOURCEENTRY>::iterator I = this->begin(); I != this->end(); ++I)
200 if (I->first.size() == 0)
201 continue;
202 RESOURCEENTRY entry = I->second;
203 for (std::vector<std::wstring>::iterator II = entry.automaticcomments.begin(); II != entry.automaticcomments.end(); ++II)
205 File << II->c_str() << _T("\n");
207 for (std::vector<std::wstring>::iterator II = entry.translatorcomments.begin(); II != entry.translatorcomments.end(); ++II)
209 File << II->c_str() << _T("\n");
211 if (I->second.resourceIDs.size() > 0)
213 File << _T("#. Resource IDs: (");
215 std::set<DWORD>::const_iterator II = I->second.resourceIDs.begin();
216 File << (*II);
217 ++II;
218 while (II != I->second.resourceIDs.end())
220 File << _T(", ");
221 File << (*II);
222 ++II;
224 File << _T(")\n");
226 if (I->second.flag.length() > 0)
227 File << (I->second.flag.c_str()) << _T("\n");
228 File << (_T("msgid \"")) << (I->first.c_str()) << _T("\"\n");
229 File << (_T("msgstr \"")) << (I->second.msgstr.c_str()) << _T("\"\n\n");
230 nEntries++;
232 File.close();
233 if (!m_bQuiet)
234 _ftprintf(stdout, _T("File %s saved, containing %d entries\n"), szPath, nEntries);
235 return TRUE;