summaryrefslogtreecommitdiffstats
path: root/kbabel/filters/gettext
diff options
context:
space:
mode:
Diffstat (limited to 'kbabel/filters/gettext')
-rw-r--r--kbabel/filters/gettext/Makefile.am20
-rw-r--r--kbabel/filters/gettext/gettextexport.cpp352
-rw-r--r--kbabel/filters/gettext/gettextexport.h88
-rw-r--r--kbabel/filters/gettext/gettextimport.cpp821
-rw-r--r--kbabel/filters/gettext/gettextimport.h70
-rw-r--r--kbabel/filters/gettext/kbabel_gettext_export.desktop53
-rw-r--r--kbabel/filters/gettext/kbabel_gettext_import.desktop53
7 files changed, 1457 insertions, 0 deletions
diff --git a/kbabel/filters/gettext/Makefile.am b/kbabel/filters/gettext/Makefile.am
new file mode 100644
index 00000000..58186306
--- /dev/null
+++ b/kbabel/filters/gettext/Makefile.am
@@ -0,0 +1,20 @@
+####### General stuff
+
+INCLUDES= -I../../common -I$(srcdir)/../../common $(all_includes)
+
+kde_module_LTLIBRARIES = kbabel_gettextimport.la kbabel_gettextexport.la
+
+kbabel_gettextimport_la_SOURCES = gettextimport.cpp
+kbabel_gettextimport_la_LIBADD = ../../common/libkbabelcommon.la
+kbabel_gettextimport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kbabel_gettextexport_la_SOURCES = gettextexport.cpp
+kbabel_gettextexport_la_LIBADD = ../../common/libkbabelcommon.la
+kbabel_gettextexport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+METASOURCES = AUTO
+
+service_DATA = kbabel_gettext_import.desktop kbabel_gettext_export.desktop
+servicedir = $(kde_servicesdir)
+
+gettextexport.lo: ../../common/kbprojectsettings.h
diff --git a/kbabel/filters/gettext/gettextexport.cpp b/kbabel/filters/gettext/gettextexport.cpp
new file mode 100644
index 00000000..e951847b
--- /dev/null
+++ b/kbabel/filters/gettext/gettextexport.cpp
@@ -0,0 +1,352 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2001-2002 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2005,2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "gettextexport.h"
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "kbprojectsettings.h"
+
+#include <qfile.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_gettextexport, KGenericFactory<GettextExportPlugin> ( "kbabelgettextexportfilter" ) )
+
+using namespace KBabel;
+
+GettextExportPlugin::GettextExportPlugin(QObject* parent, const char* name, const QStringList &) :
+ CatalogExportPlugin(parent,name), m_wrapWidth( -1 )
+{
+}
+
+ConversionStatus GettextExportPlugin::save(const QString& localFile , const QString& mimetype, const Catalog* catalog)
+{
+ // check, whether we know how to handle the extra data
+ if( catalog->importPluginID() != "GNU gettext")
+ return UNSUPPORTED_TYPE;
+
+ // we support on the application/x-gettext MIME type
+ if( mimetype != "application/x-gettext")
+ return UNSUPPORTED_TYPE;
+
+ QFile file(localFile);
+
+ if(file.open(IO_WriteOnly))
+ {
+ int progressRatio = QMAX(100/ QMAX(catalog->numberOfEntries(),1), 1);
+ emit signalResetProgressBar(i18n("saving file"),100);
+
+ QTextStream stream(&file);
+
+ SaveSettings _saveSettings = catalog->saveSettings();
+
+ if(_saveSettings.useOldEncoding && catalog->fileCodec())
+ {
+ stream.setCodec(catalog->fileCodec());
+ }
+ else
+ {
+ switch(_saveSettings.encoding)
+ {
+ case ProjectSettingsBase::UTF8:
+ stream.setCodec(QTextCodec::codecForName("utf-8"));
+ break;
+ case ProjectSettingsBase::UTF16:
+ stream.setCodec(QTextCodec::codecForName("utf-16"));
+ break;
+ default:
+ stream.setCodec(QTextCodec::codecForLocale());
+ break;
+ }
+ }
+
+ // only save header if it is not empty
+ const QString headerComment( catalog->header().comment() );
+ // ### TODO: why is this useful to have a header with an empty msgstr?
+ if( !headerComment.isEmpty() || !catalog->header().msgstr().isEmpty() )
+ {
+ // write header
+ writeComment( stream, headerComment );
+
+ const QString headerMsgid = catalog->header().msgid().first();
+
+ // Gettext PO files should have an empty msgid as header
+ if ( !headerMsgid.isEmpty() )
+ {
+ // ### TODO: perhaps it is grave enough for a user message
+ kdWarning() << "Non-empty msgid for the header, assuming empty msgid!" << endl << headerMsgid << "---" << endl;
+ }
+
+ // ### FIXME: if it is the header, then the msgid should be empty! (Even if KBabel has made something out of a non-header first entry!)
+ stream << "msgid \"\"\n";
+
+ writeKeyword( stream, "msgstr", catalog->header().msgstr().first() );
+
+ stream << "\n";
+ }
+
+ QStringList list;
+ for( uint counter = 0; counter < catalog->numberOfEntries() ; counter++ )
+ {
+ if(counter%10==0) {
+ emit signalProgress(counter/progressRatio);
+ }
+
+ // write entry
+ writeComment( stream, catalog->comment(counter) );
+
+ const QString msgctxt = catalog->msgctxt(counter);
+ if (! msgctxt.isEmpty() )
+ {
+ writeKeyword( stream, "msgctxt", msgctxt );
+ }
+
+ writeKeyword( stream, "msgid", catalog->msgid( counter ).first() );
+ if( catalog->pluralForm( counter ) == Gettext )
+ {
+ writeKeyword( stream, "msgid_plural", catalog->msgid( counter ).last() );
+ }
+
+ if( catalog->pluralForm(counter) != Gettext)
+ {
+ writeKeyword( stream, "msgstr", catalog->msgstr( counter ).first() );
+ }
+ else
+ {
+ kdDebug(KBABEL) << "Saving gettext plural form" << endl;
+ const int forms = catalog->msgstr( counter ).count();
+ for ( int i = 0; i < forms; ++i )
+ {
+ QString keyword ( "msgstr[" );
+ keyword += QString::number( i );
+ keyword += ']';
+
+ writeKeyword( stream, keyword, *( catalog->msgstr( counter ).at( i ) ) );
+ }
+ }
+
+ stream << "\n";
+
+ kapp->processEvents(10);
+ if( isStopped() )
+ {
+ return STOPPED;
+ }
+ }
+
+ if( _saveSettings.saveObsolete )
+ {
+ QValueList<QString>::ConstIterator oit;
+
+ QStringList _obsolete = catalog->catalogExtraData();
+
+ for( oit = _obsolete.begin(); oit != _obsolete.end(); ++oit )
+ {
+ stream << (*oit) << "\n\n";
+
+ kapp->processEvents(10);
+ if( isStopped() )
+ {
+ return STOPPED;
+ }
+ }
+ }
+
+ emit signalProgress(100);
+ file.close();
+
+ emit signalClearProgressBar();
+ }
+ else
+ {
+ //emit signalError(i18n("Wasn't able to open file %1").arg(filename.ascii()));
+ return OS_ERROR;
+ }
+
+ return OK;
+}
+
+void GettextExportPlugin::writeComment( QTextStream& stream, const QString& comment ) const
+{
+ if( !comment.isEmpty() )
+ {
+ // We must check that each comment line really starts with a #, to avoid syntax errors
+ int pos = 0;
+ for(;;)
+ {
+ const int newpos = comment.find( '\n', pos, false );
+ if ( newpos == pos )
+ {
+ ++pos;
+ stream << "\n";
+ continue;
+ }
+ const QString span ( ( newpos == -1 ) ? comment.mid( pos ) : comment.mid( pos, newpos-pos ) );
+
+ const int len = span.length();
+ QString spaces; // Stored leading spaces
+ for ( int i = 0 ; i < len ; ++i )
+ {
+ const QChar& ch = span[ i ];
+ if ( ch == '#' )
+ {
+ stream << spaces << span.mid( i );
+ break;
+ }
+ else if ( ch == ' ' || ch == '\t' )
+ {
+ // We have a leading white space character, so store it temporary
+ spaces += ch;
+ }
+ else
+ {
+ // Not leading white space and not a # character. so consider that the # character was missing at first position.
+ stream << "# " << spaces << span.mid( i );
+ break;
+ }
+ }
+ stream << "\n";
+
+ if ( newpos == -1 )
+ break;
+ else
+ pos = newpos + 1;
+ }
+ }
+}
+
+void GettextExportPlugin::writeKeyword( QTextStream& stream, const QString& keyword, const QString& text ) const
+{
+ if ( text.isEmpty() )
+ {
+ // Whatever the wrapping mode, an empty line is an empty line
+ stream << keyword << " \"\"\n";
+ return;
+ }
+ else if ( m_wrapWidth == -1 )
+ {
+ // Traditional KBabel wrapping
+ QStringList list = QStringList::split( '\n', text );
+
+ if ( text.startsWith( "\n" ) )
+ list.prepend( QString() );
+
+ if(list.isEmpty())
+ list.append( QString() );
+
+ if( list.count() > 1 )
+ list.prepend( QString() );
+
+ stream << keyword << " ";
+
+ QStringList::const_iterator it;
+ for( it = list.constBegin(); it != list.constEnd(); ++it )
+ {
+ stream << "\"" << (*it) << "\"\n";
+ }
+ return;
+ }
+ else if ( ( !m_wrapWidth )
+ || ( m_wrapWidth < 0 ) // Unknown special wrapping, so assume "no wrap" instead
+ )
+ {
+ // No wrapping (like Gettext's --no.wrap or -w0 )
+
+ // we need to remove the \n characters, as they are extra characters
+ QString realText( text );
+ realText.remove( '\n' );
+ stream << keyword << " \"" << realText << "\"\n";
+ return;
+ }
+
+ // ### TODO: test!
+ // Normal wrapping like Gettext's -w parameter with a value bigger than 0
+ // From here on, we assume that we have an non-empty text and a positive non-null m_wrapWidth
+
+ // we need to remove the \n characters, as they are extra characters
+ QString realText( text );
+ realText.remove( '\n' );
+
+ bool needFirstEmptyLine = false;
+ if ( realText.find( "\\n" ) != -1 )
+ {
+ // We have more than one (logical) line, so write the extra empty line
+ needFirstEmptyLine = true;
+ }
+ else
+ {
+ // We must see if the text would fit in one line, including the keyword, a space and two quote characters.
+ const int rest = text.length() + keyword.length() + 3 - m_wrapWidth;
+ if ( rest > 0 )
+ {
+ needFirstEmptyLine = true;
+ }
+ }
+ int availableWidth = m_wrapWidth;
+ if ( needFirstEmptyLine )
+ {
+ stream << keyword << " \"\"\n";
+ }
+ else
+ {
+ stream << keyword << " ";
+ availableWidth -= keyword.length();
+ availableWidth--; // The space after the keyword
+ }
+
+ const int spanLength = realText.length();
+ for ( int pos = 0; pos < spanLength; )
+ {
+ availableWidth -= 2; // Count the quote characters
+ if ( availableWidth < 2 )
+ {
+ // Be sure that at least two useful characters are written, even if the wrap width is too small
+ availableWidth = 2;
+ }
+ const int newlinePos = realText.find ( "\\n", pos );
+ if ( ( newlinePos >= 0 ) && ( newlinePos - pos + 2 < availableWidth ) )
+ {
+ // The newline is near than the maximum available numbers of characters
+ availableWidth = newlinePos - pos + 2;
+ }
+ stream << '\"' << realText.mid( pos, availableWidth ) << "\"\n";
+ pos += availableWidth;
+ }
+}
diff --git a/kbabel/filters/gettext/gettextexport.h b/kbabel/filters/gettext/gettextexport.h
new file mode 100644
index 00000000..81cbe9c4
--- /dev/null
+++ b/kbabel/filters/gettext/gettextexport.h
@@ -0,0 +1,88 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef GETTEXTEXPORTPLUGIN_H
+#define GETTEXTEXPORTPLUGIN_H
+
+#include <catalogfileplugin.h>
+
+#include <qstringlist.h>
+
+namespace KBabel {
+class Catalog;
+}
+class KURL;
+class QFile;
+class QTextCodec;
+
+/**
+ * @brief The class for exporting GNU gettext PO files.
+ *
+ * As an extra information, it stores the list of all obsolete entries.
+ */
+
+class GettextExportPlugin: public KBabel::CatalogExportPlugin
+{
+public:
+ GettextExportPlugin(QObject* parent, const char* name, const QStringList &);
+ virtual KBabel::ConversionStatus save(const QString& file, const QString& mimetype, const KBabel::Catalog* catalog);
+
+private:
+ /**
+ * Write a PO comment to @p stream and take care that each comment lines start with a # character
+ */
+ void writeComment( QTextStream& stream, const QString& comment ) const;
+
+ /**
+ * Write a PO keyword (msgctxt, msgid, msgstr, msgstr_plural, msgstr[0]) and the corresponding text.
+ * This includes wrapping the text.
+ */
+ void writeKeyword( QTextStream& stream, const QString& keyword, const QString& text ) const;
+
+public:
+ /**
+ * @brief Width of the wrap
+ *
+ * This is the width of the wrap in characters (not bytes), including everything
+ * (e.g. keyword, quote characters, spaces).
+ *
+ * - A value of 0 means no wrap
+ * - A value of -1 means the traditional KBabel wrapping
+ * - Other negative values are reserved for future extensions (by default: no wrap)
+ * @note
+ * - Gettext's default value is 78 characters
+ * - Too small values might not be correctly supported.
+ */
+ int m_wrapWidth;
+};
+
+#endif
diff --git a/kbabel/filters/gettext/gettextimport.cpp b/kbabel/filters/gettext/gettextimport.cpp
new file mode 100644
index 00000000..3f54301d
--- /dev/null
+++ b/kbabel/filters/gettext/gettextimport.cpp
@@ -0,0 +1,821 @@
+// kate: space-indent on; indent-width 3; replace-tabs on;
+
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2001-2003 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <nicolasg@snafu.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "gettextimport.h"
+
+#include <catalogitem.h>
+#include <resources.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_gettextimport, KGenericFactory<GettextImportPlugin> ( "kbabelgettextimportfilter" ) )
+
+using namespace KBabel;
+
+GettextImportPlugin::GettextImportPlugin(QObject* parent, const char* name, const QStringList &) : CatalogImportPlugin(parent,name)
+{
+}
+
+ConversionStatus GettextImportPlugin::load(const QString& filename, const QString&)
+{
+ kdDebug( KBABEL ) << k_funcinfo << endl;
+
+ if ( filename.isEmpty() ) {
+ kdDebug(KBABEL) << "fatal error: empty filename to open" << endl;
+ return NO_FILE;
+ }
+
+ QFileInfo info(filename);
+
+ if(!info.exists() || info.isDir())
+ return NO_FILE;
+
+ if(!info.isReadable())
+ return NO_PERMISSIONS;
+
+ QFile file(filename);
+
+ if ( !file.open( IO_ReadOnly ) )
+ return NO_PERMISSIONS;
+
+ uint oldPercent = 0;
+ emit signalResetProgressBar(i18n("loading file"),100);
+
+ QByteArray ba = file.readAll();
+ file.close();
+
+ // find codec for file
+ bool hadCodec;
+ QTextCodec* codec=codecForArray( ba, &hadCodec );
+
+ bool recoveredErrorInHeader = false;
+
+ QTextStream stream(ba,IO_ReadOnly);
+
+ if(codec)
+ stream.setCodec(codec);
+ else
+ {
+ kdWarning() << "No encoding declared or found, using UTF-8" << endl;
+ stream.setEncoding( QTextStream::UnicodeUTF8 );
+#ifdef __GNUC__
+# warning Default UTF-8 encoding needs to be improved
+#endif
+ // Templates define CHARSET, so if e make it a recoverable error, the template is not loadable anymore, as for templates recoverable errors are disqualifying.
+ //recoveredErrorInHeader = true;
+ }
+
+ QIODevice *dev = stream.device();
+ int fileSize = dev->size();
+
+ // if somethings goes wrong with the parsing, we don't have deleted the old contents
+ CatalogItem tempHeader;
+ QStringList tempObsolete;
+
+
+ kdDebug(KBABEL) << "start parsing..." << endl;
+
+ // first read header
+ const ConversionStatus status = readHeader(stream);
+
+
+ if ( status == RECOVERED_PARSE_ERROR )
+ {
+ kdDebug( KBABEL ) << "Recovered error in header entry" << endl;
+ recoveredErrorInHeader = true;
+ }
+ else if ( status != OK )
+ {
+ emit signalClearProgressBar();
+
+ kdDebug( KBABEL ) << "Parse error in header entry" << endl;
+ return status;
+ }
+
+ kdDebug() << "HEADER MSGID: " << _msgid << endl;
+ kdDebug() << "HEADER MSGSTR: " << _msgstr << endl;
+ if ( !_msgid.isEmpty() && !_msgid.first().isEmpty() )
+ {
+ // The header must have an empty msgid
+ kdWarning(KBABEL) << "Header entry has non-empty msgid. Creating a temporary header! " << _msgid << endl;
+ tempHeader.setMsgid( QStringList() );
+ QStringList tmp;
+ tmp.append(
+ "Content-Type: text/plain; charset=UTF-8\\n" // Unknown charset
+ "Content-Transfer-Encoding: 8bit\\n"
+ "Mime-Version: 1.0" );
+ tempHeader.setMsgstr( tmp );
+ // We keep the comment of the first entry, as it might really be a header comment (at least partially)
+ const QString comment( "# Header entry was created by KBabel!\n#\n" + _comment );
+ tempHeader.setComment( comment );
+ recoveredErrorInHeader = true;
+ }
+ else
+ {
+ tempHeader.setMsgid( _msgid );
+ tempHeader.setMsgstr( _msgstr );
+ tempHeader.setComment( _comment );
+ }
+ if(tempHeader.isFuzzy())
+ {
+ tempHeader.removeFuzzy();
+ }
+
+ // check if header seems to indicate docbook content generated by xml2pot
+ const bool docbookContent = (tempHeader.msgstr().find("application/x-xml2pot") != tempHeader.msgstr().end());
+
+ // now parse the rest of the file
+ uint counter=0;
+ QValueList<uint> errorIndex;
+ bool recoveredError=false;
+ bool docbookFile=false;
+
+ while( !stream.eof() )
+ {
+ kapp->processEvents(10);
+ if( isStopped() )
+ {
+ return STOPPED;
+ }
+
+ const ConversionStatus success=readEntry(stream);
+
+ if(success==OK)
+ {
+ if( _obsolete )
+ {
+ tempObsolete.append(_comment);
+ }
+ else
+ {
+ CatalogItem tempCatItem;
+ tempCatItem.setMsgctxt( _msgctxt );
+ tempCatItem.setMsgid( _msgid );
+ tempCatItem.setMsgstr( _msgstr );
+ tempCatItem.setComment( _comment );
+ tempCatItem.setGettextPluralForm( _gettextPluralForm );
+
+ // add new entry to the list of entries
+ appendCatalogItem(tempCatItem);
+ // check if first comment seems to indicate a docbook source file
+ if(counter==0)
+ docbookFile = ( tempCatItem.comment().find(".docbook") != -1 );
+ }
+ }
+ else if(success==RECOVERED_PARSE_ERROR)
+ {
+ kdDebug( KBABEL ) << "Recovered parse error in entry: " << counter << endl;
+ recoveredError=true;
+ errorIndex.append(counter);
+
+ CatalogItem tempCatItem;
+ tempCatItem.setMsgctxt( _msgctxt );
+ tempCatItem.setMsgid( _msgid );
+ tempCatItem.setMsgstr( _msgstr );
+ tempCatItem.setComment( _comment );
+ tempCatItem.setGettextPluralForm( _gettextPluralForm );
+
+ // add new entry to the list of entries
+ appendCatalogItem(tempCatItem);
+ }
+ else if ( success == PARSE_ERROR )
+ {
+ kdDebug( KBABEL ) << "Parse error in entry: " << counter << endl;
+ return PARSE_ERROR;
+ }
+ else
+ {
+ kdWarning( KBABEL ) << "Unknown success status, assumig parse error " << success << endl;
+ return PARSE_ERROR;
+ }
+ counter++;
+
+ const uint newPercent = (100*dev->at())/fileSize;
+ if(newPercent > oldPercent)
+ {
+ oldPercent = newPercent;
+ emit signalProgress(oldPercent);
+ }
+ }
+
+
+ // to be sure it is set to 100, if someone don't connect to
+ // signalClearProgressBar()
+ emit signalProgress(100);
+
+ emit signalClearProgressBar();
+
+
+ // ### TODO: can we check that there is no useful entry?
+ if ( !counter )
+ {
+ // Empty file? (Otherwise, there would be a try of getting an entry and the count would be 1 !)
+ kdDebug( KBABEL ) << k_funcinfo << " Empty file?" << endl;
+ return PARSE_ERROR;
+ }
+
+ kdDebug(KBABEL) << k_funcinfo << " ready" << endl;
+
+ // We have succesfully loaded the file (perhaps with recovered errors)
+
+ setGeneratedFromDocbook(docbookContent || docbookFile);
+
+ setHeader(tempHeader);
+ setCatalogExtraData(tempObsolete);
+ setErrorIndex(errorIndex);
+
+ if(hadCodec)
+ setFileCodec(codec);
+ else
+ setFileCodec(0);
+
+ setMimeTypes( "application/x-gettext" );
+
+ if ( recoveredErrorInHeader )
+ {
+ kdDebug( KBABEL ) << k_funcinfo << " Returning: header error" << endl;
+ return RECOVERED_HEADER_ERROR;
+ }
+ else if ( recoveredError )
+ {
+ kdDebug( KBABEL ) << k_funcinfo << " Returning: recovered parse error" << endl;
+ return RECOVERED_PARSE_ERROR;
+ }
+ else
+ {
+ kdDebug( KBABEL ) << k_funcinfo << " Returning: OK! :-)" << endl;
+ return OK;
+ }
+}
+
+QTextCodec* GettextImportPlugin::codecForArray(QByteArray& array, bool* hadCodec)
+{
+ if(hadCodec)
+ {
+ *hadCodec=false;
+ }
+
+ QTextStream stream( array, IO_ReadOnly );
+ // ### TODO Qt4: see if it can be done with QByteArray alone, in an encoding-neutral way.
+ // Set ISO-8859-1 as it is a relatively neutral encoding when reading (compared to UTF-8 or a random locale encoing)
+ stream.setEncoding( QTextStream::Latin1 );
+
+ // first read header
+ ConversionStatus status = readHeader(stream);
+ if(status!=OK && status != RECOVERED_PARSE_ERROR)
+ {
+ kdDebug(KBABEL) << "wasn't able to read header" << endl;
+ return 0;
+ }
+
+ const QString head = _msgstr.first();
+
+ QRegExp regexp("Content-Type:\\s*\\w+/[-\\w]+;?\\s*charset\\s*=\\s*(\\S+)\\s*\\\\n");
+ if( regexp.search( head ) == -1 )
+ {
+ kdDebug(KBABEL) << "no charset entry found" << endl;
+ return 0;
+ }
+
+ const QString charset = regexp.cap(1);
+ kdDebug(KBABEL) << "charset: " << charset << endl;
+
+ QTextCodec* codec=0;
+
+ if(!charset.isEmpty())
+ {
+ // "CHARSET" is the default charset entry in a template (pot).
+ // characters in a template should be either pure ascii or
+ // at least utf8, so utf8-codec can be used for both.
+ if( charset == "CHARSET")
+ {
+ if(hadCodec)
+ *hadCodec=false;
+
+ codec=QTextCodec::codecForName("utf8");
+ kdDebug(KBABEL)
+ << QString("file seems to be a template: using utf-8 encoding.")
+ << endl;
+ }
+ else
+ {
+ codec=QTextCodec::codecForName(charset.latin1());
+ if(hadCodec)
+ *hadCodec=true;
+ }
+
+ if(!codec)
+ {
+ kdWarning(KBABEL) << "charset found, but no codec available, using UTF-8 instead" << endl;
+ }
+ }
+ else
+ {
+ // No charset? So it is probably ASCII, therefore UTF-8
+ kdWarning(KBABEL) << "No charset defined! Assuming UTF-8!" << endl;
+ }
+
+
+ return codec;
+}
+
+ConversionStatus GettextImportPlugin::readHeader(QTextStream& stream)
+{
+ CatalogItem temp;
+ int filePos=stream.device()->at();
+ ConversionStatus status=readEntry(stream);
+
+ if(status==OK || status==RECOVERED_PARSE_ERROR)
+ {
+ // test if this is the header
+ if(!_msgid.first().isEmpty())
+ {
+ stream.device()->at(filePos);
+ }
+
+ return status;
+ }
+
+ return PARSE_ERROR;
+}
+
+ConversionStatus GettextImportPlugin::readEntry(QTextStream& stream)
+{
+ //kdDebug( KBABEL ) << k_funcinfo << " START" << endl;
+ enum {Begin,Comment,Msgctxt,Msgid,Msgstr} part=Begin;
+
+ QString line;
+ bool error=false;
+ bool recoverableError=false;
+ bool seenMsgctxt=false;
+ _msgstr.clear();
+ _msgstr.append(QString());
+ _msgid.clear();
+ _msgid.append(QString());
+ _msgctxt=QString();
+ _comment=QString();
+ _gettextPluralForm=false;
+ _obsolete=false;
+
+ QStringList::Iterator msgstrIt=_msgstr.begin();
+
+ while( !stream.eof() )
+ {
+ const int pos=stream.device()->at();
+
+ line=stream.readLine();
+
+ //kdDebug() << "Parsing line: " << line << endl;
+
+ // ### Qt4: no need of a such a check
+ if(line.isNull()) // file end
+ break;
+ else if ( line.startsWith( "<<<<<<<" ) || line.startsWith( "=======" ) || line.startsWith( ">>>>>>>" ) )
+ {
+ // We have found a CVS/SVN conflict marker. Abort.
+ // (It cannot be any useful data of the PO file, as otherwise the line would start with at least a quote)
+ kdError(KBABEL) << "CVS/SVN conflict marker found! Aborting!" << endl << line << endl;
+ return PARSE_ERROR;
+ }
+
+ // remove whitespaces from beginning and end of line
+ line=line.stripWhiteSpace();
+
+ if(part==Begin)
+ {
+ // ignore trailing newlines
+ if(line.isEmpty())
+ continue;
+
+ if(line.startsWith("#~"))
+ {
+ _obsolete=true;
+ part=Comment;
+ _comment=line;
+ }
+ else if(line.startsWith("#"))
+ {
+ part=Comment;
+ _comment=line;
+ }
+ else if(line.find(QRegExp("^msgctxt\\s*\".*\"$")) != -1)
+ {
+ part=Msgctxt;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgctxt\\s*\""));
+ line.remove(QRegExp("\"$"));
+ _msgctxt=line;
+ seenMsgctxt=true;
+ }
+ else if(line.find(QRegExp("^msgid\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no comment, msgctxt or msgid found after a comment: " << line << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Comment)
+ {
+ if(line.isEmpty() && _obsolete ) return OK;
+ if(line.isEmpty() )
+ continue;
+ else if(line.startsWith("#~"))
+ {
+ _comment+=("\n"+line);
+ _obsolete=true;
+ }
+ else if(line.startsWith("#"))
+ {
+ _comment+=("\n"+line);
+ }
+ else if(line.find(QRegExp("^msgctxt\\s*\".*\"$")) != -1)
+ {
+ part=Msgctxt;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgctxt\\s*\""));
+ line.remove(QRegExp("\"$"));
+ _msgctxt=line;
+ seenMsgctxt=true;
+ }
+ else if(line.find(QRegExp("^msgid\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no comment or msgid found after a comment while parsing: " << _comment << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Msgctxt)
+ {
+ if(line.isEmpty())
+ continue;
+ else if(line.find(QRegExp("^\".*\\n?\"$")) != -1)
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ // add Msgctxt line to item
+ if(_msgctxt.isEmpty())
+ _msgctxt=line;
+ else
+ _msgctxt+=("\n"+line);
+ }
+ else if(line.find(QRegExp("^msgid\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no msgid found after a msgctxt while parsing: " << _msgctxt << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Msgid)
+ {
+ if(line.isEmpty())
+ continue;
+ else if(line.find(QRegExp("^\".*\\n?\"$")) != -1)
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ QStringList::Iterator it;
+ if(_gettextPluralForm)
+ it = _msgid.fromLast();
+ else
+ it = _msgid.begin();
+
+ // add Msgid line to item
+ if((*it).isEmpty())
+ (*it)=line;
+ else
+ (*it)+=("\n"+line);
+ }
+ else if(line.find(QRegExp("^msgid_plural\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+ _gettextPluralForm = true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid_plural\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ _msgid.append(line);
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid_plural\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+ _gettextPluralForm = true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid_plural\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ _msgid.append(line);
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if(!_gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\s*\".*\\n?\"$")) != -1))
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+ }
+ else if(!_gettextPluralForm
+ && line.find(QRegExp("^msgstr\\s*\"?.*\\n?\"?$")) != -1)
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[0\\]\\s*\".*\\n?\"$")) != -1))
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[0\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[0\\]\\s*\"?.*\\n?\"?$")) != -1))
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[0\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if ( line.startsWith( "#" ) )
+ {
+ // ### TODO: could this be considered recoverable?
+ kdDebug(KBABEL) << "comment found after a msgid while parsing: " << _msgid.first() << endl;
+ error=true;
+ break;
+ }
+ else if ( line.startsWith( "msgid" ) )
+ {
+ kdDebug(KBABEL) << "Another msgid found after a msgid while parsing: " << _msgid.first() << endl;
+ error=true;
+ break;
+ }
+ // a line of the msgid with a missing quotation mark
+ else if(line.find(QRegExp("^\"?.+\\n?\"?$")) != -1)
+ {
+ recoverableError=true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ QStringList::Iterator it;
+ if( _gettextPluralForm )
+ it = _msgid.fromLast();
+ else
+ it = _msgid.begin();
+
+ // add Msgid line to item
+ if((*it).isEmpty())
+ (*it)=line;
+ else
+ (*it)+=("\n"+line);
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no msgstr found after a msgid while parsing: " << _msgid.first() << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Msgstr)
+ {
+ if(line.isEmpty())
+ continue;
+ // another line of the msgstr
+ else if(line.find(QRegExp("^\".*\\n?\"$")) != -1)
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ if((*msgstrIt).isEmpty())
+ (*msgstrIt)=line;
+ else
+ (*msgstrIt)+=("\n"+line);
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[[0-9]+\\]\\s*\".*\\n?\"$")) != -1))
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[[0-9]+\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ msgstrIt=_msgstr.append(line);
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[[0-9]\\]\\s*\"?.*\\n?\"?$")) != -1))
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[[0-9]\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ msgstrIt=_msgstr.append(line);
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if((line.find(QRegExp("^\\s*msgid")) != -1) || (line.find(QRegExp("^\\s*#")) != -1))
+ {
+ // We have read successfully one entry, so end loop.
+ stream.device()->at(pos);// reset position in stream to beginning of this line
+ break;
+ }
+ else if(line.startsWith("msgstr"))
+ {
+ kdDebug(KBABEL) << "Another msgstr found after a msgstr while parsing: " << _msgstr.last() << endl;
+ error=true;
+ break;
+ }
+ // another line of the msgstr with a missing quotation mark
+ else if(line.find(QRegExp("^\"?.+\\n?\"?$")) != -1)
+ {
+ recoverableError=true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ if((*msgstrIt).isEmpty())
+ (*msgstrIt)=line;
+ else
+ (*msgstrIt)+=("\n"+line);
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no msgid or comment found after a msgstr while parsing: " << _msgstr.last() << endl;
+ error=true;
+ break;
+ }
+ }
+ }
+
+/*
+ if(_gettextPluralForm)
+ {
+ kdDebug(KBABEL) << "gettext plural form:\n"
+ << "msgid:\n" << _msgid.first() << "\n"
+ << "msgid_plural:\n" << _msgid.last() << "\n" << endl;
+ int counter=0;
+ for(QStringList::Iterator it = _msgstr.begin(); it != _msgstr.end(); ++it)
+ {
+ kdDebug(KBABEL) << "msgstr[" << counter << "]:\n"
+ << (*it) << endl;
+ counter++;
+ }
+ }
+ */
+
+ //kdDebug( KBABEL ) << k_funcinfo << " NEAR RETURN" << endl;
+ if(error)
+ return PARSE_ERROR;
+ else if(recoverableError)
+ return RECOVERED_PARSE_ERROR;
+ else
+ {
+ return OK;
+ }
+}
diff --git a/kbabel/filters/gettext/gettextimport.h b/kbabel/filters/gettext/gettextimport.h
new file mode 100644
index 00000000..e28ec790
--- /dev/null
+++ b/kbabel/filters/gettext/gettextimport.h
@@ -0,0 +1,70 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef GETTEXTIMPORTPLUGIN_H
+#define GETTEXTIMPORTPLUGIN_H
+
+#include <catalogfileplugin.h>
+
+#include <qstringlist.h>
+
+class KURL;
+class QFile;
+class QTextCodec;
+
+/* ****************************************************************************
+ The class for importing GNU gettext PO files. As an extra information,
+ it stores the list of all obsolete entries.
+**************************************************************************** */
+
+class GettextImportPlugin: public KBabel::CatalogImportPlugin
+{
+public:
+ GettextImportPlugin(QObject* parent, const char* name, const QStringList &);
+ virtual KBabel::ConversionStatus load(const QString& file, const QString& mimetype);
+ virtual const QString id() { return "GNU gettext"; }
+
+private:
+ QTextCodec* codecForArray(QByteArray& arary, bool* hadCodec);
+ KBabel::ConversionStatus readHeader(QTextStream& stream);
+ KBabel::ConversionStatus readEntry(QTextStream& stream);
+
+ // description of the last read entry
+ QString _msgctxt;
+ QStringList _msgid;
+ QStringList _msgstr;
+ QString _comment;
+ bool _gettextPluralForm;
+ bool _obsolete;
+};
+
+#endif
diff --git a/kbabel/filters/gettext/kbabel_gettext_export.desktop b/kbabel/filters/gettext/kbabel_gettext_export.desktop
new file mode 100644
index 00000000..30cf0df5
--- /dev/null
+++ b/kbabel/filters/gettext/kbabel_gettext_export.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel GNU Gettext Export Filter
+Name[bg]=Филтър за експортиране на GNU Gettext - KBabel
+Name[br]=Sil ezporzh GNU Gettext evit KBabel
+Name[bs]=KBabel GNU Gettext filter za izvoz
+Name[ca]=Filtre KBabel per exportar Gettext de GNU
+Name[cs]=Exportní filtr do formátu Gettext pro KBabel
+Name[cy]=Hidl Allforio GNU Gettext KBabel
+Name[da]=KBabel GNU Gettext eksportfilter
+Name[de]=GNU Gettext-Exportfilter für KBabel
+Name[el]=Φίλτρο εξαγωγής GNU Gettext του KBabel
+Name[es]=Filtro de exportación KBabel GNU Gettext
+Name[et]=KBabeli GNU Gettexti ekspordifilter
+Name[eu]=KBabel GNU gettext esportazio iragazkia
+Name[fa]=پالایۀ صادرات KBabel GNU Gettext
+Name[fi]=KBabel GNU Gettext -vientisuodatin
+Name[fr]=filtre d'exportation GNU Gettext pour KBabel
+Name[ga]=Scagaire Easpórtála Gettext GNU le haghaidh KBabel
+Name[gl]=Filtro de exportación de GNU/gettext para KBabel
+Name[hi]=के-बेबल ग्नू गेट-टेक्स्ट निर्यात फ़िल्टर
+Name[hu]=KBabel GNU Gettext exportszűrő
+Name[is]=KBabel GNU Gettext útflutningssía
+Name[it]=Filtro di esportazione di GNU Gettext per KBabel
+Name[ja]=KBabel GNU Gettext エクスポートフィルタ
+Name[ka]=KBabel GNU Gettext ექსპორტის ფილტრი
+Name[kk]=KBabel GNU Gettext экспорттау сүзгісі
+Name[lt]=KBabel GNU Gettext eksportavimo filtras
+Name[ms]=Penapis Eksport KBabel GNU Gettext
+Name[nb]=GNU Gettext-eksportfilter for KBabel
+Name[nds]=KBabel-Exportfilter för GNU Gettext
+Name[ne]=केब्याबल जीएनयू गेटटेक्स्ट निर्यात फिल्टर
+Name[nl]=KBabel GNU Gettext Exportfilter
+Name[nn]=GNU Gettext-eksportfilter for KBabel
+Name[pa]=KBabel GNU Gettext ਨਿਰਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do eksportu do formatu GNU Gettext
+Name[pt]=Filtro de Exportação do Gettext da GNU para o KBabel
+Name[pt_BR]=Filtro de Exportação GNU Gettext do KBabel
+Name[ru]=Фильтр экспорта сообщений GNU Gettext
+Name[sk]=Exportný filter GNU gettext pre KBabel
+Name[sl]=Izvozni filter GNU Gettext za KBabel
+Name[sr]=KBabel-ов филтер за извоз у GNU Gettext
+Name[sr@Latn]=KBabel-ov filter za izvoz u GNU Gettext
+Name[sv]=Kbabel exportfilter för GNU Gettext
+Name[ta]=Kபாபேல் GNU உரை எடு ஏற்றுமதி வடிகட்டி
+Name[tg]=Филтри содироти хабарҳо GNU Gettext
+Name[tr]=KBabel GNU Gettext Dışa Aktarma Süzgeci
+Name[uk]=Фільтр експорту GNU Gettext для KBabel
+Name[zh_CN]=KBabel GNU Gettext 导出过滤器
+Name[zh_TW]=KBabel GNU Gettext 匯出過濾器
+X-KDE-Library=kbabel_gettextexport
+X-KDE-Export=application/x-gettext
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/gettext/kbabel_gettext_import.desktop b/kbabel/filters/gettext/kbabel_gettext_import.desktop
new file mode 100644
index 00000000..c6b1b293
--- /dev/null
+++ b/kbabel/filters/gettext/kbabel_gettext_import.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel GNU Gettext Import Filter
+Name[bg]=Филтър за импортиране на GNU Gettext - KBabel
+Name[br]=Sil enporzh GNU Gettext evit KBabel
+Name[bs]=KBabel GNU Gettext filter za uvoz
+Name[ca]=Filtre KBabel per importar Gettext de GNU
+Name[cs]=Importní filtr Gettext pro KBabel
+Name[cy]=Hidl Mewnforio GNU Gettext KBabel
+Name[da]=KBabel GNU Gettext Import-filter
+Name[de]=GNU Gettext-Importfilter für KBabel
+Name[el]=Φίλτρο εισαγωγής GNU Gettext του KBabel
+Name[es]=Filtro de importación KBabel GNU Gettext
+Name[et]=KBabeli GNU Gettexti impordifilter
+Name[eu]=KBabel GNU gettext inportazio iragazkia
+Name[fa]=پالایۀ واردات KBabel GNU Gettext
+Name[fi]=KBabel GNU Gettext -tuontisuodatin
+Name[fr]=Filtre d'importation GNU Gettext pour KBabel
+Name[ga]=Scagaire Iompórtála Gettext GNU le haghaidh KBabel
+Name[gl]=Filtro de importación de GNU/gettext para KBabel
+Name[hi]=के-बेबल ग्नू गेट-टेक्स्ट आयात फ़िल्टर
+Name[hu]=KBabel GNU Gettext importszűrő
+Name[is]=KBabel GNU Gettext innflutningssía
+Name[it]=Filtro di importazione di GNU Gettext per KBabel
+Name[ja]=KBabel GNU Gettext インポートフィルタ
+Name[ka]=KBabel GNU Gettext იმპორის ფილტრი
+Name[kk]=KBabel GNU Gettext импорттау сүзгісі
+Name[lt]=KBabel GNU Gettext importavimo filtras
+Name[ms]=Penapis Import KBabel GNU Gettext
+Name[nb]=GNU Gettext-importfilter for KBabel
+Name[nds]=KBabel-Importfilter för GNU Gettext
+Name[ne]=केब्याबल जीएनयू गेटटेक्स्ट आयात फिल्टर
+Name[nl]=KBabel GNU Gettext Importfilter
+Name[nn]=GNU Gettext-importfilter for KBabel
+Name[pa]=KBabel GNU Gettext ਅਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do importu z formatu GNU Gettext
+Name[pt]=Filtro de Importação de Gettext da GNU para o KBabel
+Name[pt_BR]=Filtro de Importação GNU Gettext para o KBabel
+Name[ru]=Фильтр импорта сообщений GNU Gettext
+Name[sk]=Importný filter GNU gettext pre KBabel
+Name[sl]=Uvozni filter GNU Gettext za KBabel
+Name[sr]=KBabel-ов филтер за увоз из GNU Gettext-а
+Name[sr@Latn]=KBabel-ov filter za uvoz iz GNU Gettext-a
+Name[sv]=Kbabel importfilter för GNU Gettext
+Name[ta]=Kபாபேல் GNU உரை எடு இறக்குமதி வடிகட்டி
+Name[tg]=Филтри воридоти хабарҳо GNU Gettext
+Name[tr]=KBabel GNU Gettext İçe Aktarma Süzgeci
+Name[uk]=Фільтр імпорту GNU Gettext для KBabel
+Name[zh_CN]=KBabel GNU Gettext 导入过滤器
+Name[zh_TW]=KBabel GNU Gettext 匯入過濾器
+X-KDE-Library=kbabel_gettextimport
+X-KDE-Import=application/x-gettext
+ServiceTypes=KBabelFilter