1 /**
2 @file
3 @author Stefan Frings
4 */
5
6 #include "template.h"
7 #include <QFileInfo>
8 #include <QRegularExpression>
9
Template(QString source,QString sourceName)10 Template::Template(QString source, QString sourceName)
11 : QString(source)
12 {
13 this->sourceName=sourceName;
14 this->warnings=false;
15 }
16
Template(QFile & file,QTextCodec * textCodec)17 Template::Template(QFile& file, QTextCodec* textCodec)
18 {
19 this->warnings=false;
20 sourceName=QFileInfo(file.fileName()).baseName();
21 if (file.open(QFile::ReadOnly | QFile::Text))
22 {
23 QByteArray data=file.readAll();
24 file.close();
25
26 if(textCodec)
27 append(textCodec->toUnicode(data));
28 else
29 append(fromUtf8(data));
30 }
31 else
32 {
33 qCritical("Template: cannot read from %s, %s",qPrintable(sourceName),qPrintable(file.errorString()));
34 }
35 }
36
37
setVariable(QString name,QString value)38 int Template::setVariable(QString name, QString value)
39 {
40 int count=0;
41 QString variable="{"+name+"}";
42 int start=indexOf(variable);
43 while (start>=0)
44 {
45 replace(start, variable.length(), value);
46 count++;
47 start=indexOf(variable,start+value.length());
48 }
49 if (count==0 && warnings)
50 {
51 qWarning("Template: missing variable %s in %s",qPrintable(variable),qPrintable(sourceName));
52 }
53 return count;
54 }
55
setCondition(QString name,bool value)56 int Template::setCondition(QString name, bool value)
57 {
58 int count=0;
59 QString startTag=QString("{if %1}").arg(name);
60 QString elseTag=QString("{else %1}").arg(name);
61 QString endTag=QString("{end %1}").arg(name);
62 // search for if-else-end
63 int start=indexOf(startTag);
64 while (start>=0)
65 {
66 int end=indexOf(endTag,start+startTag.length());
67 if (end>=0)
68 {
69 count++;
70 int ellse=indexOf(elseTag,start+startTag.length());
71 if (ellse>start && ellse<end)
72 {
73 // there is an else part
74 if (value==true)
75 {
76 QString truePart=mid(start+startTag.length(), ellse-start-startTag.length());
77 replace(start, end-start+endTag.length(), truePart);
78 }
79 else
80 {
81 // value==false
82 QString falsePart=mid(ellse+elseTag.length(), end-ellse-elseTag.length());
83 replace(start, end-start+endTag.length(), falsePart);
84 }
85 }
86 else if (value==true)
87 {
88 // and no else part
89 QString truePart=mid(start+startTag.length(), end-start-startTag.length());
90 replace(start, end-start+endTag.length(), truePart);
91 }
92 else
93 {
94 // value==false and no else part
95 replace(start, end-start+endTag.length(), "");
96 }
97 start=indexOf(startTag,start);
98 }
99 else
100 {
101 qWarning("Template: missing condition end %s in %s",qPrintable(endTag),qPrintable(sourceName));
102 }
103 }
104 // search for ifnot-else-end
105 QString startTag2="{ifnot "+name+"}";
106 start=indexOf(startTag2);
107 while (start>=0)
108 {
109 int end=indexOf(endTag,start+startTag2.length());
110 if (end>=0)
111 {
112 count++;
113 int ellse=indexOf(elseTag,start+startTag2.length());
114 if (ellse>start && ellse<end)
115 {
116 // there is an else part
117 if (value==false)
118 {
119 QString falsePart=mid(start+startTag2.length(), ellse-start-startTag2.length());
120 replace(start, end-start+endTag.length(), falsePart);
121 }
122 else
123 {
124 // value==true
125 QString truePart=mid(ellse+elseTag.length(), end-ellse-elseTag.length());
126 replace(start, end-start+endTag.length(), truePart);
127 }
128 }
129 else if (value==false)
130 {
131 // and no else part
132 QString falsePart=mid(start+startTag2.length(), end-start-startTag2.length());
133 replace(start, end-start+endTag.length(), falsePart);
134 }
135 else
136 {
137 // value==true and no else part
138 replace(start, end-start+endTag.length(), "");
139 }
140 start=indexOf(startTag2,start);
141 }
142 else
143 {
144 qWarning("Template: missing condition end %s in %s",qPrintable(endTag),qPrintable(sourceName));
145 }
146 }
147 if (count==0 && warnings)
148 {
149 qWarning("Template: missing condition %s or %s in %s",qPrintable(startTag),qPrintable(startTag2),qPrintable(sourceName));
150 }
151 return count;
152 }
153
loop(QString name,int repetitions)154 int Template::loop(QString name, int repetitions)
155 {
156 Q_ASSERT(repetitions>=0);
157 int count=0;
158 QString startTag="{loop "+name+"}";
159 QString elseTag="{else "+name+"}";
160 QString endTag="{end "+name+"}";
161 // search for loop-else-end
162 int start=indexOf(startTag);
163 while (start>=0)
164 {
165 int end=indexOf(endTag,start+startTag.length());
166 if (end>=0)
167 {
168 count++;
169 int ellse=indexOf(elseTag,start+startTag.length());
170 if (ellse>start && ellse<end)
171 {
172 // there is an else part
173 if (repetitions>0)
174 {
175 QString loopPart=mid(start+startTag.length(), ellse-start-startTag.length());
176 QString insertMe;
177 for (int i=0; i<repetitions; ++i)
178 {
179 // number variables, conditions and sub-loop within the loop
180 QString nameNum=name+QString::number(i);
181 QString s=loopPart;
182 s.replace(QString("{%1.").arg(name), QString("{%1.").arg(nameNum));
183 s.replace(QString("{if %1.").arg(name), QString("{if %1.").arg(nameNum));
184 s.replace(QString("{ifnot %1.").arg(name), QString("{ifnot %1.").arg(nameNum));
185 s.replace(QString("{else %1.").arg(name), QString("{else %1.").arg(nameNum));
186 s.replace(QString("{end %1.").arg(name), QString("{end %1.").arg(nameNum));
187 s.replace(QString("{loop %1.").arg(name), QString("{loop %1.").arg(nameNum));
188 insertMe.append(s);
189 }
190 replace(start, end-start+endTag.length(), insertMe);
191 }
192 else
193 {
194 // repetitions==0
195 QString elsePart=mid(ellse+elseTag.length(), end-ellse-elseTag.length());
196 replace(start, end-start+endTag.length(), elsePart);
197 }
198 }
199 else if (repetitions>0)
200 {
201 // and no else part
202 QString loopPart=mid(start+startTag.length(), end-start-startTag.length());
203 QString insertMe;
204 for (int i=0; i<repetitions; ++i)
205 {
206 // number variables, conditions and sub-loop within the loop
207 QString nameNum=name+QString::number(i);
208 QString s=loopPart;
209 s.replace(QString("{%1.").arg(name), QString("{%1.").arg(nameNum));
210 s.replace(QString("{if %1.").arg(name), QString("{if %1.").arg(nameNum));
211 s.replace(QString("{ifnot %1.").arg(name), QString("{ifnot %1.").arg(nameNum));
212 s.replace(QString("{else %1.").arg(name), QString("{else %1.").arg(nameNum));
213 s.replace(QString("{end %1.").arg(name), QString("{end %1.").arg(nameNum));
214 s.replace(QString("{loop %1.").arg(name), QString("{loop %1.").arg(nameNum));
215 insertMe.append(s);
216 }
217 replace(start, end-start+endTag.length(), insertMe);
218 }
219 else
220 {
221 // repetitions==0 and no else part
222 replace(start, end-start+endTag.length(), "");
223 }
224 start=indexOf(startTag,start);
225 }
226 else
227 {
228 qWarning("Template: missing loop end %s in %s",qPrintable(endTag),qPrintable(sourceName));
229 }
230 }
231 if (count==0 && warnings)
232 {
233 qWarning("Template: missing loop %s in %s",qPrintable(startTag),qPrintable(sourceName));
234 }
235 return count;
236 }
237
enableWarnings(bool enable)238 void Template::enableWarnings(bool enable)
239 {
240 warnings=enable;
241 }
242
translate(ITemplateTranslationProvider & provider)243 void Template::translate(ITemplateTranslationProvider &provider)
244 {
245 //This regex captures expressions of the form
246 //<?= tr("This is a test") ?> and <?= tr("optional %1 parameters %2","bla","blu") ?>
247 //The first capture group is the key (untranslated string), the second the optional list of parameters
248 static const QRegularExpression regexp = QRegularExpression("<\\?=\\s*tr\\(\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"((?:,\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")*)\\s*\\)\\?>");
249 //This one is used to extract the parameters using global matching
250 static const QRegularExpression paramExp = QRegularExpression(",\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"");
251
252 int offset = 0;
253 QRegularExpressionMatch match;
254 do
255 {
256 match = regexp.match(*this,offset);
257
258 if(match.hasMatch())
259 {
260 int start = match.capturedStart(0);
261 int len = match.capturedLength(0);
262 QString key = match.captured(1);
263
264 //replace escaped double and single quotes
265 key.replace("\\\"","\"");
266 key.replace("\\'", "'");
267
268 QString translation = provider.getTranslation(key);
269
270 //find out if we have optional parameters
271 if(match.capturedLength(2)>0)
272 {
273 QString params = match.captured(2);
274 //extract each optional parameter
275 QRegularExpressionMatchIterator it = paramExp.globalMatch(params);
276 while(it.hasNext())
277 {
278 QRegularExpressionMatch paramMatch = it.next();
279 QString param = paramMatch.captured(1);
280
281 //replace escaped quotes
282 param.replace("\\\"","\"");
283 param.replace("\\'", "'");
284
285 //apply the param
286 translation = translation.arg(param);
287 }
288 }
289
290 this->replace(start,len,translation);
291 offset = start+translation.length();
292 }
293 }while(match.hasMatch());
294 }
295