1/* This file is part of the KDE project
2 Copyright (C) 2010 Luigi Toscano <luigi.toscano@tiscali.it>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library 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 GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <QCoreApplication>
22#include <QDebug>
23#include <QDir>
24#include <QFile>
25#include <QIODevice>
26#include <QList>
27#include <QPair>
28#include <QRegExp>
29#include <QStringList>
30#include <QTextStream>
31
32
33class LangListType: public QList<QPair<QString,QString> >
34{
35public:
36 int searchLang( QString el ) {
37
38 for ( int i = 0; i < size(); ++i ) {
39 if ( at( i ).first == el )
40 return i;
41 }
42 return -1;
43 }
44};
45
46int writeLangFile( const QString &fname, const QString &dtdPath,
47 const LangListType &langMap ) {
48
49 QFile outFile( fname );
50 if ( ! outFile.open( QIODevice::WriteOnly ) ) {
51 qCritical() << QString( "Could not write %1" )
52 .arg( outFile.fileName() );
53 return( 1 );
54 }
55
56 QTextStream outStream( &outFile );
57 outStream << "<?xml version='1.0'?>" << endl;
58 outStream << QString( "<!DOCTYPE l:i18n SYSTEM \"%1\" [" )
59 .arg( dtdPath ) << endl;
60
61 LangListType::const_iterator i = langMap.constBegin();
62 while ( i != langMap.constEnd() ) {
63 //qDebug() << (*i).first << ": " << (*i).second;
64 outStream << QString( "<!ENTITY %1 SYSTEM \"%2\">" )
65 .arg( (*i).first ).arg( (*i).second ) << endl;
66 ++i;
67 }
68 outStream << "]>" << endl;
69
70 if ( langMap.size() > 0 ) {
71 outStream
72 << "<l:i18n xmlns:l=\"http://docbook.sourceforge.net/xmlns/l10n/1.0\">"
73 << endl;
74 i = langMap.constBegin();
75 while ( i != langMap.constEnd() ) {
76 outStream << QString( "&%1;" )
77 .arg( (*i).first ) << endl;
78 ++i;
79 }
80 outStream << "</l:i18n>" << endl;
81 }
82
83 outFile.close();
84
85 return( 0 );
86}
87
88int writeLangFileNew( const QString &fname, const QString &dtdPath,
89 const LangListType &langMap ) {
90
91 QFile outFile( fname );
92 if ( ! outFile.open( QIODevice::WriteOnly ) ) {
93 qCritical() << QString( "Could not write %1" )
94 .arg( outFile.fileName() );
95 return( 1 );
96 }
97
98 QTextStream outStream( &outFile );
99 outStream << "<?xml version='1.0'?>" << endl;
100 outStream << QString( "<!DOCTYPE l:i18n SYSTEM \"%1\">" )
101 .arg( dtdPath ) << endl;
102
103 if ( langMap.size() > 0 ) {
104 outStream
105 << "<l:i18n xmlns:l=\"http://docbook.sourceforge.net/xmlns/l10n/1.0\">"
106 << endl;
107 LangListType::const_iterator i = langMap.constBegin();
108 while ( i != langMap.constEnd() ) {
109 outStream << QString( "<l:l10n language=\"%1\" href=\"%2\"/>" )
110 .arg( (*i).first ).arg( (*i).second ) << endl;
111 ++i;
112 }
113 outStream << "</l:i18n>" << endl;
114 }
115
116 outFile.close();
117
118 return( 0 );
119}
120
121inline const QString addTrailingSlash( const QString &p ) {
122 return p.endsWith( "/" ) ? p : p + "/";
123}
124
125int main( int argc, char **argv ) {
126 QCoreApplication app( argc, argv );
127
128 const QStringList arguments = app.arguments();
129 if ( arguments.count() != 4 ) {
130 qCritical() << "wrong argument count";
131 return ( 1 );
132 }
133
134 const QString l10nDir = addTrailingSlash( arguments[1] );
135 const QString l10nCustomDir = addTrailingSlash( arguments[2] );
136 const QString destDir = addTrailingSlash( arguments[3] );
137
138 QFile i18nFile( l10nDir + "common/l10n.xml" );
139
140 if ( ! i18nFile.open( QIODevice::ReadOnly ) ) {
141 qCritical() << i18nFile.fileName() << " not found";
142 return( 1 );
143 }
144
145 const QString all10nFName = destDir + "all-l10n.xml";
146 const QString customl10nFName = destDir + "kde-custom-l10n.xml";
147
148 /*
149 * for each language defined in the original l10n.xml, copy
150 * it into all-l10n.xml and store it in a list;
151 **/
152 QRegExp rxEntity, rxEntity2, rxDocType, rxDocType2;
153 rxDocType.setPattern("^\\s*<!DOCTYPE\\s+l:i18n\\s+SYSTEM\\s+\"l10n\\.dtd\"\\s+\\[\\s*$");
154 rxDocType2.setPattern("^\\s*<!DOCTYPE\\s+l:i18n\\s+SYSTEM\\s+\"l10n\\.dtd\"\\s*>$");
155 rxEntity.setPattern("^\\s*<!ENTITY\\s+([^\\s]+)\\s+SYSTEM\\s+\"([^\\s]+)\">\\s*$");
156 rxEntity2.setPattern("^\\s*<l:l10n language=\"([^\\s]+)\"\\s+href=\"([^\\s]+)\"/>\\s*$");
157 QTextStream inStream( &i18nFile );
158 int parsingState = 0;
159
160 LangListType allLangs, customLangs;
161
162 bool foundRxEntity = false;
163 bool foundRxEntity2 = false;
164 while ( ! inStream.atEnd() ) {
165 QString line = inStream.readLine();
166
167 switch ( parsingState ) {
168 case 0:
169 if ( rxDocType.indexIn( line ) != -1 ) {
170 parsingState = 1;
171 //qDebug() << "DTD found";
172 } else if ( rxDocType2.indexIn( line ) != -1 ) {
173 parsingState = 1;
174 //qDebug() << "DTD found";
175 }
176 break;
177 case 1:
178 QString langCode, langFile;
179 if ( rxEntity.indexIn( line ) != -1 && !foundRxEntity2 ) {
180 foundRxEntity = true;
181 langCode = rxEntity.cap( 1 );
182 langFile = l10nDir + "common/" + rxEntity.cap( 2 );
183 allLangs += qMakePair( langCode, langFile );
184 //qDebug() << langCode << " - " << langFile;
185 } else if ( rxEntity2.indexIn( line ) != -1 && !foundRxEntity ) {
186 foundRxEntity2 = true;
187 langCode = rxEntity2.cap( 1 );
188 langFile = l10nDir + "common/" + rxEntity2.cap( 2 );
189 allLangs += qMakePair( langCode, langFile );
190 //qDebug() << langCode << " - " << langFile;
191 }
192 break;
193 }
194
195 }
196 i18nFile.close();
197
198 /* read the list of locally-available custom languages */
199 QDir outDir( l10nCustomDir );
200
201 QStringList dirFileFilters;
202 dirFileFilters << "*.xml";
203 QStringList customLangFiles = outDir.entryList( dirFileFilters,
204 QDir::Files|QDir::NoSymLinks, QDir::Name );
205 /* the following two calls to removeOne should not be needed, as
206 * the customization directory from the sources should not contain
207 * those files
208 */
209 customLangFiles.removeOne( "all-l10n.xml" );
210 customLangFiles.removeOne( "kde-custom-l10n.xml" );
211 //qDebug() << "customLangFiles:" << customLangFiles;
212
213 /*
214 * for each custom language (from directory listing), if it is not
215 * in the list of upstream languages, add it to all-l10n.xml,
216 * otherwise add it to kde-custom-l10n.xml
217 */
218 QStringList::const_iterator i = customLangFiles.constBegin();
219 while ( i != customLangFiles.constEnd() ) {
220 QString langFile = (*i);
221 /* remove trailing .xml */
222 QString langCode = langFile.left( langFile.length() - 4 );
223
224 QPair<QString,QString> cl = qMakePair( langCode, langFile );
225 if ( ( allLangs.searchLang( langCode ) ) > 0 ) {
226 /* custom language found in upstream list */
227 customLangs += cl;
228 } else {
229 /* custom language not found in upstream list */
230 allLangs += cl;
231 }
232 ++i;
233 }
234
235 int res = 0;
236
237 if ( foundRxEntity ) {
238 /* old style (docbook-xsl<=1.75) */
239 res = writeLangFile( all10nFName, l10nDir + "common/l10n.dtd",
240 allLangs );
241 } else {
242 res = writeLangFileNew( all10nFName, l10nDir + "common/l10n.dtd",
243 allLangs );
244 }
245
246 return( res );
247}
248