• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdesdk API Reference
  • KDE Home
  • Contact Us
 

lokalize

  • sources
  • kde-4.14
  • kdesdk
  • lokalize
  • src
  • catalog
  • gettext
gettextstorage.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2008 Nick Shaforostoff <shaforostoff@kde.ru>
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of
7 the License or (at your option) version 3 or any later version
8 accepted by the membership of KDE e.V. (or its successor approved
9 by the membership of KDE e.V.), which shall act as a proxy
10 defined in Section 14 of version 3 of the license.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "gettextstorage.h"
22 
23 #include "gettextheader.h"
24 #include "catalogitem_private.h"
25 #include "gettextimport.h"
26 #include "gettextexport.h"
27 
28 #include "project.h"
29 
30 #include "version.h"
31 #include "prefs_lokalize.h"
32 
33 #include "diff.h"
34 
35 #include <QProcess>
36 #include <QString>
37 #include <QMap>
38 
39 #include <kdebug.h>
40 
41 // static QString GNUPluralForms(const QString& lang);
42 
43 using namespace GettextCatalog;
44 
45 GettextStorage::GettextStorage()
46  : CatalogStorage()
47 {
48 }
49 
50 
51 GettextStorage::~GettextStorage()
52 {
53 }
54 
55 //BEGIN OPEN/SAVE
56 
57 int GettextStorage::load(QIODevice* device/*, bool readonly*/)
58 {
59  //GettextImportPlugin importer=GettextImportPlugin(readonly?(new ExtraDataSaver()):(new ExtraDataListSaver()));
60  GettextImportPlugin importer;
61  ConversionStatus status = OK;
62  int errorLine;
63  status = importer.open(device,this,&errorLine);
64 
65  //for langs with more than 2 forms
66  //we create any form-entries additionally needed
67  uint i=0;
68  uint lim=size();
69  while (i<lim)
70  {
71  CatalogItem& item=m_entries[i];
72  if (item.isPlural()
73  && item.msgstrPlural().count()<m_numberOfPluralForms
74  )
75  {
76  QVector<QString> msgstr(item.msgstrPlural());
77  while (msgstr.count()<m_numberOfPluralForms)
78  msgstr.append(QString());
79  item.setMsgstr(msgstr);
80  }
81  ++i;
82 
83  }
84  //qCompress(m_storage->m_catalogExtraData.join("\n\n").toUtf8(),9);
85 
86  return status==OK?0:(errorLine+1);
87 }
88 
89 bool GettextStorage::save(QIODevice* device, bool belongsToProject)
90 {
91  QString header=m_header.msgstr();
92  QString comment=m_header.comment();
93  QString catalogProjectId;//=m_url.fileName();
94  //catalogProjectId=catalogProjectId.left(catalogProjectId.lastIndexOf('.'));
95  updateHeader(header,
96  comment,
97  m_targetLangCode,
98  m_numberOfPluralForms,
99  catalogProjectId,
100  m_generatedFromDocbook,
101  belongsToProject,
102  /*forSaving*/true,
103  m_codec);
104  m_header.setMsgstr(header);
105  m_header.setComment(comment);
106 
107  //GettextExportPlugin exporter(m_maxLineLength>70?m_maxLineLength:-1, m_trailingNewLines);// this is kinda hackish...
108  GettextExportPlugin exporter(Project::instance()->wordWrap(), m_trailingNewLines);
109 
110  ConversionStatus status = OK;
111  status = exporter.save(device/*x-gettext-translation*/,this, m_codec);
112 
113  return status==OK;
114 }
115 
116 //END OPEN/SAVE
117 
118 //BEGIN STORAGE TRANSLATION
119 
120 int GettextStorage::size() const
121 {
122  return m_entries.size();
123 }
124 
125 
126 static const QChar altSep(156);
127 static InlineTag makeInlineTag(int i)
128 {
129  static const QString altSepText(" | ");
130  static const QString ctype=i18n("separator for different-length string alternatives");
131  return InlineTag(i,i,InlineTag::x,QString::number(i),QString(),altSepText,ctype);
132 }
133 
134 static CatalogString makeCatalogString(const QString& string)
135 {
136  CatalogString result;
137  result.string=string;
138 
139  int i=0;
140 
141  while((i=result.string.indexOf(altSep, i))!=-1)
142  {
143  result.string[i]=TAGRANGE_IMAGE_SYMBOL;
144  result.tags.append(makeInlineTag(i));
145  ++i;
146  }
147  return result;
148 }
149 
150 //flat-model interface (ignores XLIFF grouping)
151 CatalogString GettextStorage::sourceWithTags(DocPosition pos) const
152 {
153  return makeCatalogString(source(pos));
154 }
155 CatalogString GettextStorage::targetWithTags(DocPosition pos) const
156 {
157  return makeCatalogString(target(pos));
158 }
159 
160 QString GettextStorage::source(const DocPosition& pos) const
161 {
162  return m_entries.at(pos.entry).msgid(pos.form);
163 }
164 QString GettextStorage::target(const DocPosition& pos) const
165 {
166  return m_entries.at(pos.entry).msgstr(pos.form);
167 }
168 
169 void GettextStorage::targetDelete(const DocPosition& pos, int count)
170 {
171  m_entries[pos.entry].d->_msgstrPlural[pos.form].remove(pos.offset, count);
172 }
173 void GettextStorage::targetInsert(const DocPosition& pos, const QString& arg)
174 {
175  m_entries[pos.entry].d->_msgstrPlural[pos.form].insert(pos.offset, arg);
176 }
177 void GettextStorage::setTarget(const DocPosition& pos, const QString& arg)
178 {
179  m_entries[pos.entry].d->_msgstrPlural[pos.form]=arg;
180 }
181 
182 
183 void GettextStorage::targetInsertTag(const DocPosition& pos, const InlineTag& tag)
184 {
185  Q_UNUSED(tag);
186  targetInsert(pos,altSep);
187 }
188 
189 InlineTag GettextStorage::targetDeleteTag(const DocPosition& pos)
190 {
191  targetDelete(pos,1);
192  return makeInlineTag(pos.offset);
193 }
194 
195 QStringList GettextStorage::sourceAllForms(const DocPosition& pos, bool stripNewLines) const
196 {
197  return m_entries.at(pos.entry).allPluralForms(CatalogItem::Source, stripNewLines);
198 }
199 
200 QStringList GettextStorage::targetAllForms(const DocPosition& pos, bool stripNewLines) const
201 {
202  return m_entries.at(pos.entry).allPluralForms(CatalogItem::Target, stripNewLines);
203 }
204 
205 QVector<AltTrans> GettextStorage::altTrans(const DocPosition& pos) const
206 {
207  QStringList prev=m_entries.at(pos.entry).comment().split('\n').filter(QRegExp("^#\\|"));
208 
209  QString oldSingular;
210  QString oldPlural;
211 
212  QString* cur=&oldSingular;
213  QStringList::iterator it=prev.begin();
214  static const QString msgid_plural_alt="#| msgid_plural \"";
215  while (it!=prev.end())
216  {
217  if (it->startsWith(msgid_plural_alt))
218  cur=&oldPlural;
219 
220  int start=it->indexOf('\"')+1;
221  int end=it->lastIndexOf('\"');
222  if (start&&end!=-1)
223  {
224  if (!cur->isEmpty())
225  (*cur)+='\n';
226  if (!( cur->isEmpty() && (end-start)==0 ))//for multiline msgs
227  (*cur)+=it->midRef(start,end-start);
228  }
229  ++it;
230  }
231  if (pos.form==0)
232  cur=&oldSingular;
233 
234  cur->replace("\\\"","\"");
235 
236  QVector<AltTrans> result;
237  if (!cur->isEmpty())
238  result<<AltTrans(CatalogString(*cur), i18n("Previous source value, saved by Gettext during transition to a newer POT template"));
239 
240  return result;
241 }
242 
243 Note GettextStorage::setNote(DocPosition pos, const Note& note)
244 {
245  //kWarning()<<"s"<<m_entries.at(pos.entry).comment();
246  Note oldNote;
247  QVector<Note> l=notes(pos);
248  if (l.size()) oldNote=l.first();
249 
250  QStringList comment=m_entries.at(pos.entry).comment().split('\n');
251  //remove previous comment;
252  QStringList::iterator it=comment.begin();
253  while (it!=comment.end())
254  {
255  if (it->startsWith("# "))
256  it=comment.erase(it);
257  else
258  ++it;
259  }
260  if (note.content.size())
261  comment.prepend("# "+note.content.split('\n').join("\n# "));
262  m_entries[pos.entry].setComment(comment.join("\n"));
263 
264  //kWarning()<<"e"<<m_entries.at(pos.entry).comment();
265  return oldNote;
266 }
267 
268 QVector<Note> GettextStorage::notes(const DocPosition& docPosition, const QRegExp& re, int preLen) const
269 {
270  QVector<Note> result;
271  QString content;
272 
273  QStringList note=m_entries.at(docPosition.entry).comment().split('\n').filter(re);
274 
275  foreach(const QString &s, note)
276  {
277  if (s.size()>=preLen)
278  {
279  content+=s.midRef(preLen);
280  content+='\n';
281  }
282  }
283 
284  if (!content.isEmpty())
285  {
286  content.chop(1);
287  result<<Note(content);
288  }
289  return result;
290 
291 //i18nc("@info PO comment parsing. contains filename","<i>Place:</i>");
292 //i18nc("@info PO comment parsing","<i>GUI place:</i>");
293 }
294 
295 QVector<Note> GettextStorage::notes(const DocPosition& docPosition) const
296 {
297  static const QRegExp nre("^# ");
298  return notes(docPosition,nre,2);
299 }
300 
301 QVector<Note> GettextStorage::developerNotes(const DocPosition& docPosition) const
302 {
303  static const QRegExp dnre("^#\\. (?!i18n: file:)");
304  return notes(docPosition,dnre,3);
305 }
306 
307 QStringList GettextStorage::sourceFiles(const DocPosition& pos) const
308 {
309  QStringList result;
310  QStringList commentLines=m_entries.at(pos.entry).comment().split('\n');
311 
312  static const QRegExp i18n_file_re("^#. i18n: file: ");
313  foreach(const QString &uiLine, commentLines.filter(i18n_file_re))
314  {
315  result+=uiLine.mid(15).split(' ');
316  }
317 
318  bool hasUi=!result.isEmpty();
319  static const QRegExp cpp_re("^#: ");
320  foreach(const QString &cppLine, commentLines.filter(cpp_re))
321  {
322  if (hasUi && cppLine.startsWith("#: rc.cpp")) continue;
323  QStringList cppFiles=cppLine.mid(3).split(' ');
324  result+=cppFiles;
325  }
326  return result;
327 }
328 
329 QStringList GettextStorage::context(const DocPosition& pos) const
330 {
331  return matchData(pos);
332 }
333 
334 QStringList GettextStorage::matchData(const DocPosition& pos) const
335 {
336  QString ctxt=m_entries.at(pos.entry).msgctxt();
337 
338  //KDE-specific
339  //Splits @info:whatsthis and actual note
340 /* if (ctxt.startsWith('@') && ctxt.contains(' '))
341  {
342  QStringList result(ctxt.section(' ',0,0,QString::SectionSkipEmpty));
343  result<<ctxt.section(' ',1,-1,QString::SectionSkipEmpty);
344  return result;
345  }*/
346  return QStringList(ctxt);
347 }
348 
349 QString GettextStorage::id(const DocPosition& pos) const
350 {
351  //entries in gettext format may be non-unique
352  //only if their msgctxts are different
353 
354  QString result=source(pos);
355  result.remove('\n');
356  result.prepend(m_entries.at(pos.entry).msgctxt()+":\n");
357  return result;
358 /* QByteArray result=source(pos).toUtf8();
359  result+=m_entries.at(pos.entry).msgctxt().toUtf8();
360  return QString qChecksum(result);*/
361 }
362 
363 bool GettextStorage::isPlural(const DocPosition& pos) const
364 {
365  return m_entries.at(pos.entry).isPlural();
366 }
367 
368 bool GettextStorage::isApproved(const DocPosition& pos) const
369 {
370  return !m_entries.at(pos.entry).isFuzzy();
371 }
372 void GettextStorage::setApproved(const DocPosition& pos, bool approved)
373 {
374  if (approved)
375  m_entries[pos.entry].unsetFuzzy();
376  else
377  m_entries[pos.entry].setFuzzy();
378 }
379 
380 bool GettextStorage::isEmpty(const DocPosition& pos) const
381 {
382  return m_entries.at(pos.entry).isUntranslated();
383 }
384 
385 //END STORAGE TRANSLATION
386 
387 
388 
389 
390 //called from importer
391 bool GettextStorage::setHeader(const CatalogItem& newHeader)
392 {
393  if(newHeader.isValid())
394  {
395  // normalize the values - ensure every key:value pair is only on a single line
396  QString values = newHeader.msgstr();
397  values.replace ("\\n", "\\n\n");
398 // kDebug () << "Normalized header: " << values;
399  QString comment=newHeader.comment();
400  QString catalogProjectId;//=m_url.fileName(); FIXME m_url is always empty
401  //catalogProjectId=catalogProjectId.left(catalogProjectId.lastIndexOf('.'));
402  bool belongsToProject=m_url.path().contains(Project::instance()->poDir());
403 
404  updateHeader(values,
405  comment,
406  m_targetLangCode,
407  m_numberOfPluralForms,
408  catalogProjectId,
409  m_generatedFromDocbook,
410  belongsToProject,
411  /*forSaving*/true,
412  m_codec);
413  m_header=newHeader;
414  m_header.setComment(comment);
415  m_header.setMsgstr(values);
416 
417 // setClean(false);
418  //emit signalHeaderChanged();
419 
420  return true;
421  }
422  kWarning () << "header Not valid";
423  return false;
424 }
425 
426 
427 
GettextCatalog::GettextStorage::save
bool save(QIODevice *device, bool belongsToProject=false)
Definition: gettextstorage.cpp:89
QIODevice
GettextCatalog::GettextStorage::isApproved
bool isApproved(const DocPosition &pos) const
Definition: gettextstorage.cpp:368
GettextCatalog::CatalogItem::isValid
bool isValid() const
Definition: catalogitem.cpp:112
altSep
static const QChar altSep(156)
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
project.h
GettextCatalog::GettextStorage::targetInsert
void targetInsert(const DocPosition &pos, const QString &arg)
Definition: gettextstorage.cpp:173
GettextCatalog::GettextStorage::notes
QVector< Note > notes(const DocPosition &pos) const
Definition: gettextstorage.cpp:295
QVector::append
void append(const T &value)
TAGRANGE_IMAGE_SYMBOL
#define TAGRANGE_IMAGE_SYMBOL
Definition: catalogstring.h:33
GettextCatalog::GettextStorage::sourceWithTags
CatalogString sourceWithTags(DocPosition pos) const
Definition: gettextstorage.cpp:151
GettextCatalog::GettextStorage::developerNotes
QVector< Note > developerNotes(const DocPosition &pos) const
Definition: gettextstorage.cpp:301
QChar
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QString::prepend
QString & prepend(QChar ch)
catalogitem_private.h
GettextCatalog::CatalogItem
This class represents an entry in a catalog.
Definition: catalogitem.h:55
GettextCatalog::GettextExportPlugin
The class for exporting GNU gettext PO files.
Definition: gettextexport.h:53
Project::instance
static Project * instance()
Definition: project.cpp:67
QString::size
int size() const
Note
Definition: note.h:29
GettextCatalog::GettextStorage::id
QString id(const DocPosition &pos) const
entry id unique for this file
Definition: gettextstorage.cpp:349
QList::erase
iterator erase(iterator pos)
CatalogStorage::m_numberOfPluralForms
int m_numberOfPluralForms
Definition: catalogstorage.h:156
QVector::first
T & first()
CatalogString::string
QString string
Definition: catalogstring.h:130
QStringList::join
QString join(const QString &separator) const
GettextCatalog::GettextStorage::~GettextStorage
~GettextStorage()
Definition: gettextstorage.cpp:51
GettextCatalog::GettextStorage::altTrans
QVector< AltTrans > altTrans(const DocPosition &pos) const
Definition: gettextstorage.cpp:205
QString::remove
QString & remove(int position, int n)
QString::chop
void chop(int n)
GettextCatalog::GettextStorage::targetWithTags
CatalogString targetWithTags(DocPosition pos) const
Definition: gettextstorage.cpp:155
GettextCatalog::GettextStorage::isEmpty
bool isEmpty(const DocPosition &pos) const
Definition: gettextstorage.cpp:380
CatalogStorage::m_url
KUrl m_url
Definition: catalogstorage.h:152
DocPosition::offset
uint offset
Definition: pos.h:51
DocPosition::entry
int entry
Definition: pos.h:48
DocPosition
This struct represents a position in a catalog.
Definition: pos.h:38
QRegExp
GettextCatalog::GettextStorage::sourceAllForms
QStringList sourceAllForms(const DocPosition &pos, bool stripNewLines=false) const
all plural forms. pos.form doesn't matter
Definition: gettextstorage.cpp:195
QString::number
QString number(int n, int base)
QList::append
void append(const T &value)
GettextCatalog::CatalogItem::Source
Definition: catalogitem.h:88
GettextCatalog::GettextStorage::matchData
QStringList matchData(const DocPosition &pos) const
user-invisible data for matching, e.g.
Definition: gettextstorage.cpp:334
content
static QString content(QDomElement elem, ContentEditingData *data=0)
walks through XLIFF XML and performs actions depending on ContentEditingData:
Definition: tsstorage.cpp:170
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
GettextCatalog::GettextStorage::context
QStringList context(const DocPosition &pos) const
Definition: gettextstorage.cpp:329
DocPosition::form
char form
Definition: pos.h:50
makeInlineTag
static InlineTag makeInlineTag(int i)
Definition: gettextstorage.cpp:127
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
gettextheader.h
GettextCatalog::ConversionStatus
ConversionStatus
Result of the conversion.
Definition: catalogfileplugin.h:53
CatalogStorage::m_targetLangCode
QString m_targetLangCode
Definition: catalogstorage.h:154
QString
diff.h
GettextCatalog::GettextStorage::source
QString source(const DocPosition &pos) const
flat-model interface (ignores XLIFF grouping)
Definition: gettextstorage.cpp:160
CatalogStorage
Abstract interface for storage of translation file.
Definition: catalogstorage.h:45
QList::iterator
QStringList
GettextCatalog::GettextStorage::setNote
Note setNote(DocPosition pos, const Note &note)
Definition: gettextstorage.cpp:243
GettextCatalog::GettextStorage::sourceFiles
QStringList sourceFiles(const DocPosition &pos) const
Definition: gettextstorage.cpp:307
QList::end
iterator end()
GettextCatalog::GettextStorage::targetDelete
void targetDelete(const DocPosition &pos, int count)
edit operations used by undo/redo system and sync-mode
Definition: gettextstorage.cpp:169
QString::midRef
QStringRef midRef(int position, int n) const
GettextCatalog::CatalogItem::comment
QString comment() const
Definition: catalogitem.cpp:62
GettextCatalog::CatalogItem::msgstrPlural
const QVector< QString > & msgstrPlural() const
Definition: catalogitem.cpp:96
version.h
Note::content
QString content
Definition: note.h:33
QString::replace
QString & replace(int position, int n, QChar after)
CatalogString
data structure used to pass info about inline elements a XLIFF tag is represented by a TAGRANGE_IMAGE...
Definition: catalogstring.h:128
QString::mid
QString mid(int position, int n) const
QVector< QString >
GettextCatalog::GettextStorage::setApproved
void setApproved(const DocPosition &pos, bool approved)
Definition: gettextstorage.cpp:372
prefs_lokalize.h
GettextCatalog::CatalogItem::setComment
void setComment(const QString &com)
Definition: catalogitem.cpp:187
GettextCatalog::CatalogItem::msgstr
const QString & msgstr(const int form=0) const
Definition: catalogitem.cpp:78
GettextCatalog::GettextStorage::load
int load(QIODevice *device)
Definition: gettextstorage.cpp:57
CatalogString::tags
QList< InlineTag > tags
Definition: catalogstring.h:131
makeCatalogString
static CatalogString makeCatalogString(const QString &string)
Definition: gettextstorage.cpp:134
GettextCatalog::GettextStorage::targetAllForms
QStringList targetAllForms(const DocPosition &pos, bool stripNewLines=false) const
Definition: gettextstorage.cpp:200
GettextCatalog::GettextStorage::size
int size() const
Definition: gettextstorage.cpp:120
GettextCatalog::GettextStorage::targetDeleteTag
InlineTag targetDeleteTag(const DocPosition &)
Definition: gettextstorage.cpp:189
updateHeader
void updateHeader(QString &header, QString &comment, QString &langCode, int &numberOfPluralForms, const QString &CatalogProjectId, bool generatedFromDocbook, bool belongsToProject, bool forSaving, QTextCodec *codec)
Definition: gettextheader.cpp:245
QVector::count
int count(const T &value) const
InlineTag::x
Definition: catalogstring.h:61
gettextexport.h
GettextCatalog::GettextStorage::setTarget
void setTarget(const DocPosition &pos, const QString &arg)
Definition: gettextstorage.cpp:177
gettextstorage.h
GettextCatalog::CatalogItem::setMsgstr
void setMsgstr(const QString &msg, const int form=0)
Definition: catalogitem.cpp:163
GettextCatalog::GettextExportPlugin::save
ConversionStatus save(QIODevice *device, const GettextStorage *catalog, QTextCodec *codec)
Definition: gettextexport.cpp:63
GettextCatalog::GettextStorage::target
QString target(const DocPosition &pos) const
Definition: gettextstorage.cpp:164
QList::prepend
void prepend(const T &value)
GettextCatalog::GettextStorage::targetInsertTag
void targetInsertTag(const DocPosition &, const InlineTag &)
Definition: gettextstorage.cpp:183
GettextCatalog::CatalogItem::isPlural
bool isPlural() const
Definition: catalogitem.cpp:202
gettextimport.h
QStringList::filter
QStringList filter(const QString &str, Qt::CaseSensitivity cs) const
GettextCatalog::GettextImportPlugin
The class for importing GNU gettext PO files.
Definition: gettextimport.h:70
GettextCatalog::GettextStorage::GettextStorage
GettextStorage()
Definition: gettextstorage.cpp:45
QVector::size
int size() const
GettextCatalog::GettextStorage::isPlural
bool isPlural(const DocPosition &pos) const
Definition: gettextstorage.cpp:363
QList::begin
iterator begin()
AltTrans
Definition: alttrans.h:30
InlineTag
data structure used to pass info about inline elements a XLIFF tag is represented by a TAGRANGE_IMAGE...
Definition: catalogstring.h:44
GettextCatalog::CatalogImportPlugin::open
ConversionStatus open(QIODevice *, GettextStorage *catalog, int *errorLine)
Load the file and fill the corresponding catalog.
Definition: importplugin.cpp:101
GettextCatalog::CatalogItem::Target
Definition: catalogitem.h:88
GettextCatalog::OK
Definition: catalogfileplugin.h:54
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:40:07 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

lokalize

Skip menu "lokalize"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdesdk API Reference

Skip menu "kdesdk API Reference"
  • kapptemplate
  • kcachegrind
  • kompare
  • lokalize
  • umbrello
  •   umbrello

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal