OSDN Git Service

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