~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/kvilib/system/kvi_locale.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//=============================================================================
2
 
//
3
 
//   File : kvi_locale.cpp
4
 
//   Creation date : Fri Mar 19 1999 19:08:41 by Szymon Stefanek
5
 
//
6
 
//   This file is part of the KVirc irc client distribution
7
 
//   Copyright (C) 1999-2008 Szymon Stefanek (pragma at kvirc dot net)
8
 
//
9
 
//   This program is FREE software. You can redistribute it and/or
10
 
//   modify it under the terms of the GNU General Public License
11
 
//   as published by the Free Software Foundation; either version 2
12
 
//   of the License, or (at your opinion) any later version.
13
 
//
14
 
//   This program is distributed in the HOPE that it will be USEFUL,
15
 
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
 
//   See the GNU General Public License for more details.
18
 
//
19
 
//   You should have received a copy of the GNU General Public License
20
 
//   along with this program. If not, write to the Free Software Foundation,
21
 
//   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
 
//
23
 
//=============================================================================
24
 
 
25
 
 
26
 
 
27
 
//#define _KVI_DEBUG_CHECK_RANGE_
28
 
#include "kvi_debug.h"
29
 
#include "kvi_malloc.h"
30
 
#include "kvi_bswap.h"
31
 
 
32
 
#define _KVI_LOCALE_CPP_
33
 
#include "kvi_locale.h"
34
 
 
35
 
#include <QtGlobal>
36
 
#include <QTextCodec>
37
 
#include <QDir>
38
 
#include <QLocale>
39
 
#include <QByteArray>
40
 
 
41
 
#include "kvi_string.h"
42
 
#include "kvi_env.h"
43
 
#include "kvi_fileutils.h"
44
 
#include "kvi_file.h"
45
 
 
46
 
 
47
 
KVILIB_API KviMessageCatalogue           * g_pMainCatalogue       = 0;
48
 
 
49
 
static KviStr                              g_szLang;
50
 
static KviTranslator                     * g_pTranslator          = 0;
51
 
static KviPointerHashTable<const char *,KviMessageCatalogue> * g_pCatalogueDict       = 0;
52
 
static QTextCodec                        * g_pUtf8TextCodec       = 0;
53
 
 
54
 
 
55
 
/////////////////////////////////////////////////////////////////////////////////////
56
 
//
57
 
// The following code was extracted and adapted from gutf8.c
58
 
// from the GNU GLIB2 package.
59
 
//
60
 
// gutf8.c - Operations on UTF-8 strings.
61
 
//
62
 
// Copyright (C) 1999 Tom Tromey
63
 
// Copyright (C) 2000 Red Hat, Inc.
64
 
//
65
 
// This library is free software; you can redistribute it and/or
66
 
// modify it under the terms of the GNU Lesser General Public
67
 
// License as published by the Free Software Foundation; either
68
 
// version 2 of the License, or (at your option) any later version.
69
 
//
70
 
// This library is distributed in the hope that it will be useful,
71
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
72
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
73
 
// Lesser General Public License for more details.
74
 
//
75
 
// You should have received a copy of the GNU Lesser General Public
76
 
// License along with this library; if not, write to the
77
 
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
78
 
// Boston, MA 02111-1307, USA.
79
 
//
80
 
/////////////////////////////////////////////////////////////////////////////////////
81
 
 
82
 
typedef char gchar;
83
 
typedef unsigned char guchar;
84
 
typedef signed int gssize;
85
 
typedef unsigned int gunichar;
86
 
 
87
 
#define UNICODE_VALID(Char)                  \
88
 
        ((Char) < 0x110000 &&                    \
89
 
        (((Char) & 0xFFFFF800) != 0xD800) &&     \
90
 
        ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
91
 
        ((Char) & 0xFFFE) != 0xFFFE)
92
 
 
93
 
#define CONTINUATION_CHAR                            \
94
 
        if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ \
95
 
                goto error;                                     \
96
 
                val <<= 6;                                      \
97
 
                val |= (*(guchar *)p) & 0x3f;
98
 
 
99
 
 
100
 
static const char *
101
 
fast_validate (const char *str)
102
 
{
103
 
        gunichar val = 0;
104
 
        gunichar min = 0;
105
 
        const gchar *p;
106
 
 
107
 
        for (p = str; *p; p++)
108
 
        {
109
 
                if (*(guchar *)p < 128)
110
 
                        /* done */;
111
 
                else
112
 
                {
113
 
                        const gchar *last;
114
 
 
115
 
                        last = p;
116
 
                        if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
117
 
                        {
118
 
                                if ((*(guchar *)p & 0x1e) == 0)
119
 
                                        goto error;
120
 
                                p++;
121
 
                                if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */
122
 
                                        goto error;
123
 
                        }
124
 
                        else
125
 
                        {
126
 
                                if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
127
 
                                {
128
 
                                        min = (1 << 11);
129
 
                                        val = *(guchar *)p & 0x0f;
130
 
                                        goto TWO_REMAINING;
131
 
                                }
132
 
                                else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
133
 
                                {
134
 
                                        min = (1 << 16);
135
 
                                        val = *(guchar *)p & 0x07;
136
 
                                }
137
 
                                else goto error;
138
 
 
139
 
                                p++;
140
 
                                CONTINUATION_CHAR;
141
 
                                TWO_REMAINING:
142
 
                                p++;
143
 
                                CONTINUATION_CHAR;
144
 
                                p++;
145
 
                                CONTINUATION_CHAR;
146
 
 
147
 
                                if (val < min) goto error;
148
 
 
149
 
                                if (!UNICODE_VALID(val)) goto error;
150
 
                        }
151
 
 
152
 
                        continue;
153
 
 
154
 
                        error:
155
 
                        return last;
156
 
                }
157
 
        }
158
 
 
159
 
        return p;
160
 
}
161
 
 
162
 
static const gchar *
163
 
fast_validate_len (const char *str, gssize max_len)
164
 
{
165
 
        gunichar val = 0;
166
 
        gunichar min = 0;
167
 
        const gchar *p;
168
 
 
169
 
        for (p = str; (max_len < 0 || (p - str) < max_len) && *p; p++)
170
 
        {
171
 
                if (*(guchar *)p < 128)
172
 
                        /* done */;
173
 
                else
174
 
                {
175
 
                        const gchar *last;
176
 
 
177
 
                        last = p;
178
 
                        if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
179
 
                        {
180
 
                        if (max_len >= 0 && max_len - (p - str) < 2)
181
 
                                goto error;
182
 
 
183
 
                        if ((*(guchar *)p & 0x1e) == 0)
184
 
                                goto error;
185
 
                        p++;
186
 
                        if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */
187
 
                                goto error;
188
 
                        }
189
 
                        else
190
 
                        {
191
 
                                if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
192
 
                                {
193
 
                                        if (max_len >= 0 && max_len - (p - str) < 3)
194
 
                                        goto error;
195
 
 
196
 
                                        min = (1 << 11);
197
 
                                        val = *(guchar *)p & 0x0f;
198
 
                                        goto TWO_REMAINING;
199
 
                                }
200
 
                                else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
201
 
                                {
202
 
                                        if (max_len >= 0 && max_len - (p - str) < 4)
203
 
                                        goto error;
204
 
 
205
 
                                        min = (1 << 16);
206
 
                                        val = *(guchar *)p & 0x07;
207
 
                                }
208
 
                                else
209
 
                                        goto error;
210
 
 
211
 
                                p++;
212
 
                                CONTINUATION_CHAR;
213
 
                                TWO_REMAINING:
214
 
                                p++;
215
 
                                CONTINUATION_CHAR;
216
 
                                p++;
217
 
                                CONTINUATION_CHAR;
218
 
 
219
 
                                if (val < min) goto error;
220
 
                                if (!UNICODE_VALID(val)) goto error;
221
 
                        }
222
 
 
223
 
                        continue;
224
 
 
225
 
                        error:
226
 
                        return last;
227
 
                }
228
 
        }
229
 
 
230
 
        return p;
231
 
}
232
 
 
233
 
static bool g_utf8_validate (const char   *str,
234
 
                                gssize        max_len,
235
 
                                const gchar **end)
236
 
{
237
 
        const gchar *p;
238
 
 
239
 
        if (max_len < 0)
240
 
                p = fast_validate (str);
241
 
        else
242
 
                p = fast_validate_len (str, max_len);
243
 
 
244
 
        if (end) *end = p;
245
 
 
246
 
        if ((max_len >= 0 && p != str + max_len) ||
247
 
        (max_len < 0 && *p != '\0'))
248
 
                return false;
249
 
        else
250
 
                return true;
251
 
}
252
 
 
253
 
/////////////////////////////////////////////////////////////////////////////////////
254
 
//   End of gutf8.c
255
 
/////////////////////////////////////////////////////////////////////////////////////
256
 
 
257
 
 
258
 
class KviSmartTextCodec : public QTextCodec
259
 
{
260
 
protected:
261
 
        QByteArray  m_szName;
262
 
        QTextCodec * m_pRecvCodec;
263
 
        QTextCodec * m_pSendCodec;
264
 
public:
265
 
        KviSmartTextCodec(const char * szName,const char * szChildCodecName,bool bSendInUtf8)
266
 
        : QTextCodec()
267
 
        {
268
 
                m_szName = szName;
269
 
                if(!g_pUtf8TextCodec)
270
 
                {
271
 
                        g_pUtf8TextCodec = QTextCodec::codecForName("UTF-8");
272
 
                        if(!g_pUtf8TextCodec)
273
 
                        {
274
 
                                debug("Can't find the global utf8 text codec!");
275
 
                                g_pUtf8TextCodec = QTextCodec::codecForLocale(); // try anything else...
276
 
                        }
277
 
                }
278
 
                m_pRecvCodec = QTextCodec::codecForName(szChildCodecName);
279
 
                if(!m_pRecvCodec)
280
 
                {
281
 
                        debug("Can't find the codec for name %s (composite codec creation)",szName);
282
 
                        m_pRecvCodec = g_pUtf8TextCodec;
283
 
                }
284
 
                if(bSendInUtf8)
285
 
                        m_pSendCodec = g_pUtf8TextCodec;
286
 
                else
287
 
                        m_pSendCodec = m_pRecvCodec;
288
 
        }
289
 
public:
290
 
        bool ok(){ return m_pRecvCodec && g_pUtf8TextCodec; };
291
 
 
292
 
        virtual int mibEnum () const { return 0; };
293
 
 
294
 
        virtual QByteArray name() const { return m_szName; };
295
 
protected:
296
 
        virtual QByteArray convertFromUnicode(const QChar * input,int number,ConverterState * state) const
297
 
        {
298
 
                return m_pSendCodec->fromUnicode(input,number,state);
299
 
        }
300
 
        virtual QString convertToUnicode(const char * chars,int len,ConverterState * state) const
301
 
        {
302
 
                if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len,state);
303
 
                return m_pRecvCodec->toUnicode(chars,len,state);
304
 
        }
305
 
};
306
 
 
307
 
static KviPointerHashTable<const char *,KviSmartTextCodec>   * g_pSmartCodecDict      = 0;
308
 
 
309
 
 
310
 
 
311
 
/////////////////////////////////////////////////////////////////////////////////////
312
 
//
313
 
//   The following code was extracted and adapted from gettext.h and gettextP.h
314
 
//   from the GNU gettext package.
315
 
//
316
 
//   Internal header for GNU gettext internationalization functions.
317
 
//   Copyright (C) 1995, 1997 Free Software Foundation, Inc.
318
 
//
319
 
//   This program is free software; you can redistribute it and/or modify
320
 
//   it under the terms of the GNU General Public License as published by
321
 
//   the Free Software Foundation; either version 2, or (at your option)
322
 
//   any later version.
323
 
//
324
 
//   This program is distributed in the hope that it will be useful,
325
 
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
326
 
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
327
 
//   GNU General Public License for more details.
328
 
//
329
 
//   You should have received a copy of the GNU Library General Public
330
 
//   License along with the GNU C Library; see the file COPYING.LIB.  If not,
331
 
//   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
332
 
//   Boston, MA 02111-1307, USA.
333
 
//
334
 
/////////////////////////////////////////////////////////////////////////////////////
335
 
 
336
 
#include <stdio.h>
337
 
 
338
 
/*
339
 
#if HAVE_LIMITS_H || _LIBC
340
 
        #include <limits.h>
341
 
#endif
342
 
*/
343
 
 
344
 
// The magic number of the GNU message catalog format.
345
 
#define KVI_LOCALE_MAGIC 0x950412de
346
 
#define KVI_LOCALE_MAGIC_SWAPPED 0xde120495
347
 
 
348
 
// Revision number of the currently used .mo (binary) file format.
349
 
#define MO_REVISION_NUMBER 0
350
 
 
351
 
 
352
 
// Header for binary .mo file format.
353
 
struct GnuMoFileHeader
354
 
{
355
 
        // The magic number.
356
 
        kvi_u32_t magic;
357
 
        // The revision number of the file format.
358
 
        kvi_u32_t revision;
359
 
        // The number of strings pairs.
360
 
        kvi_u32_t nstrings;
361
 
        // Offset of table with start offsets of original strings.
362
 
        kvi_u32_t orig_tab_offset;
363
 
        // Offset of table with start offsets of translation strings.
364
 
        kvi_u32_t trans_tab_offset;
365
 
        // Size of hashing table.
366
 
        kvi_u32_t hash_tab_size;
367
 
        // Offset of first hashing entry.
368
 
        kvi_u32_t hash_tab_offset;
369
 
};
370
 
 
371
 
struct GnuMoStringDescriptor
372
 
{
373
 
        // Length of addressed string.
374
 
        kvi_u32_t length;
375
 
        // Offset of string in file.
376
 
        kvi_u32_t offset;
377
 
};
378
 
 
379
 
#define KVI_SWAP_IF_NEEDED(flag,value) (flag ? kvi_swap32(value) : (value))
380
 
 
381
 
////////////////////////////////////////////////////////////////////////////////////////   End of gettext.h & gettextP.h
382
 
//////////////////////////////////////////////////////////////////////////////////////
383
 
 
384
 
// HELPERS
385
 
 
386
 
static int somePrimeNumbers[90]=
387
 
{
388
 
        257 , 521 , 769 , 1031, 1087, 1091, 1103, 1117, 1123, 1151, // Incomplete *.mo files
389
 
        1163, 1171, 1181, 1193, 1201, 1213, 1217, 1223, 1229, 1231, // Complete *.mo files
390
 
        1237, 1249, 1259, 1277, 1283, 1289, 1291, 1297, 1307, 1319,
391
 
        1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1433,
392
 
        1447, 1459, 1471, 1481, 1493, 1511, 1523, 1531, 1543, 1553,
393
 
        1567, 1571, 1583, 1597, 1609, 1619, 1627, 1637, 1657, 1667, // Too big for KVIrc *.mo files
394
 
        1693, 1709, 1721, 1733, 1741, 1753, 1777, 1789, 1811, 1831,
395
 
        1907, 2069, 2111, 2221, 2309, 2441, 2531, 2617, 2731, 2837,
396
 
        2903, 3121, 3329, 3331, 3767, 4127, 5051, 6089, 7039, 9973
397
 
};
398
 
 
399
 
int kvi_getFirstBiggerPrime(int number)
400
 
{
401
 
        for(int i=0;i<90;i++){
402
 
                if(somePrimeNumbers[i] >= number)return somePrimeNumbers[i];
403
 
        }
404
 
        return 9973; //error!
405
 
}
406
 
 
407
 
 
408
 
KviMessageCatalogue::KviMessageCatalogue()
409
 
{
410
 
        //m_uEncoding = 0;
411
 
        m_pTextCodec = QTextCodec::codecForLocale();
412
 
 
413
 
        //m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(1123,true,false); // dictSize, case sensitive , don't copy keys
414
 
        m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(32,true,false); // dictSize, case sensitive , don't copy keys
415
 
        m_pMessages->setAutoDelete(true);
416
 
}
417
 
 
418
 
KviMessageCatalogue::~KviMessageCatalogue()
419
 
{
420
 
        if(m_pMessages)
421
 
                delete m_pMessages;
422
 
}
423
 
 
424
 
bool KviMessageCatalogue::load(const QString& name)
425
 
{
426
 
        QString szCatalogueFile(name);
427
 
 
428
 
        // Try to load the header
429
 
        KviFile f(szCatalogueFile);
430
 
        if(!f.open(QFile::ReadOnly))
431
 
        {
432
 
                debug("[KviLocale]: Failed to open the messages file %s: probably doesn't exist",KviQString::toUtf8(szCatalogueFile).data());
433
 
                return false;
434
 
        }
435
 
 
436
 
        GnuMoFileHeader hdr;
437
 
 
438
 
        if(f.read((char *)&hdr,sizeof(GnuMoFileHeader)) < (int)sizeof(GnuMoFileHeader))
439
 
        {
440
 
                debug("KviLocale: Failed to read header of %s",KviQString::toUtf8(szCatalogueFile).data());
441
 
                f.close();
442
 
                return false;
443
 
        }
444
 
 
445
 
        bool bMustSwap = false;
446
 
 
447
 
        if(hdr.magic != KVI_LOCALE_MAGIC)
448
 
        {
449
 
                if(hdr.magic == KVI_LOCALE_MAGIC_SWAPPED)
450
 
                {
451
 
                        debug("KviLocale: Swapped magic for file %s: swapping data too",KviQString::toUtf8(szCatalogueFile).data());
452
 
                        bMustSwap = true;
453
 
                } else {
454
 
                        debug("KviLocale: Bad locale magic for file %s: not a *.mo file ?",KviQString::toUtf8(szCatalogueFile).data());
455
 
                        f.close();
456
 
                        return false;
457
 
                }
458
 
        }
459
 
 
460
 
        if(KVI_SWAP_IF_NEEDED(bMustSwap,hdr.revision) != MO_REVISION_NUMBER)
461
 
        {
462
 
                debug("KviLocale: Invalid *.mo file revision number for file %s",KviQString::toUtf8(szCatalogueFile).data());
463
 
                f.close();
464
 
                return false;
465
 
        }
466
 
 
467
 
        int numberOfStrings = KVI_SWAP_IF_NEEDED(bMustSwap,hdr.nstrings);
468
 
 
469
 
        if(numberOfStrings <= 0)
470
 
        {
471
 
                debug("KviLocale: No translated messages found in file %s",KviQString::toUtf8(szCatalogueFile).data());
472
 
                f.close();
473
 
                return false;
474
 
        }
475
 
 
476
 
        if(numberOfStrings >= 9972)
477
 
        {
478
 
                debug("Number of strings too big...sure that it is a KVIrc catalog file ?");
479
 
                numberOfStrings = 9972;
480
 
        }
481
 
 
482
 
        // return back
483
 
        f.seek(0);
484
 
 
485
 
        unsigned int fSize = f.size();
486
 
        char * buffer = (char *)kvi_malloc(fSize);
487
 
 
488
 
        // FIXME: maybe read it in blocks eh ?
489
 
        if(f.read(buffer,fSize) < (int)fSize)
490
 
        {
491
 
                debug("KviLocale: Error while reading the translation file %s",KviQString::toUtf8(szCatalogueFile).data());
492
 
                kvi_free(buffer);
493
 
                f.close();
494
 
                return false;
495
 
        }
496
 
 
497
 
        // Check for broken *.mo files
498
 
        if(fSize < (24 + (sizeof(GnuMoStringDescriptor) * numberOfStrings)))
499
 
        {
500
 
                debug("KviLocale: Broken translation file %s (too small for all descriptors)",KviQString::toUtf8(szCatalogueFile).data());
501
 
                kvi_free(buffer);
502
 
                f.close();
503
 
                return false;
504
 
        }
505
 
 
506
 
        GnuMoStringDescriptor * origDescriptor  = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.orig_tab_offset));
507
 
        GnuMoStringDescriptor * transDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.trans_tab_offset));
508
 
 
509
 
        // Check again for broken *.mo files
510
 
        int expectedFileSize = KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].offset) +
511
 
                        KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].length);
512
 
 
513
 
        if(fSize < (unsigned int)expectedFileSize)
514
 
        {
515
 
                debug("KviLocale: Broken translation file %s (too small for all the message strings)",KviQString::toUtf8(szCatalogueFile).data());
516
 
                kvi_free(buffer);
517
 
                f.close();
518
 
                return false;
519
 
        }
520
 
 
521
 
        // Ok...we can run now
522
 
 
523
 
        int dictSize = kvi_getFirstBiggerPrime(numberOfStrings);
524
 
        if(m_pMessages)
525
 
                delete m_pMessages;
526
 
        m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(dictSize,true,false); // dictSize, case sensitive , don't copy keys
527
 
        m_pMessages->setAutoDelete(true);
528
 
 
529
 
        KviStr szHeader;
530
 
 
531
 
        for(int i=0;i < numberOfStrings;i++)
532
 
        {
533
 
                // FIXME: "Check for NULL inside strings here ?"
534
 
                //debug("original seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset),
535
 
                //      KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length));
536
 
                //debug("translated seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset),
537
 
                //      KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length));
538
 
 
539
 
                KviTranslationEntry * e = new KviTranslationEntry(
540
 
                        (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset)),
541
 
                        KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length),
542
 
                        (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset)),
543
 
                        KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length));
544
 
 
545
 
                // In some (or all?) *.mo files the first string
546
 
                // is zero bytes long and the translated one contains
547
 
                // information about the translation
548
 
                if(e->m_szKey.len() == 0)
549
 
                {
550
 
                        szHeader = e->m_szEncodedTranslation;
551
 
                        delete e;
552
 
                        continue;
553
 
                }
554
 
 
555
 
                m_pMessages->insert(e->m_szKey.ptr(),e);
556
 
        }
557
 
 
558
 
        kvi_free(buffer);
559
 
        f.close();
560
 
 
561
 
        m_pTextCodec = 0;
562
 
 
563
 
        // find out the text encoding , if possible
564
 
        if(szHeader.hasData())
565
 
        {
566
 
                // find "charset=*\n"
567
 
                int idx = szHeader.findFirstIdx("charset=");
568
 
                if(idx != -1)
569
 
                {
570
 
                        szHeader.cutLeft(idx + 8);
571
 
                        szHeader.cutFromFirst('\n');
572
 
                        szHeader.trimmed();
573
 
                        m_pTextCodec = KviLocale::codecForName(szHeader.ptr());
574
 
                        if(!m_pTextCodec)
575
 
                        {
576
 
                                debug("Can't find the codec for charset=%s",szHeader.ptr());
577
 
                                debug("Falling back to codecForLocale()");
578
 
                                m_pTextCodec = QTextCodec::codecForLocale();
579
 
                        }
580
 
                }
581
 
        }
582
 
 
583
 
        if(!m_pTextCodec)
584
 
        {
585
 
                debug("The message catalogue does not have a \"charset\" header");
586
 
                debug("Assuming utf8"); // FIXME: or codecForLocale() ?
587
 
                m_pTextCodec = QTextCodec::codecForName("UTF-8");
588
 
        }
589
 
 
590
 
        return true;
591
 
}
592
 
 
593
 
const char * KviMessageCatalogue::translate(const char *text)
594
 
{
595
 
        KviTranslationEntry * aux = m_pMessages->find(text);
596
 
        if(aux)return aux->m_szEncodedTranslation.ptr();
597
 
        return text;
598
 
}
599
 
 
600
 
const QString & KviMessageCatalogue::translateToQString(const char *text)
601
 
{
602
 
        KviTranslationEntry * aux = m_pMessages->find(text);
603
 
        if(aux)
604
 
        {
605
 
                if(aux->m_pQTranslation)return *(aux->m_pQTranslation);
606
 
                aux->m_pQTranslation = new QString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr()));
607
 
                return *(aux->m_pQTranslation);
608
 
        }
609
 
        // no translation is available: let's avoid continous string decoding
610
 
        aux = new KviTranslationEntry(text);
611
 
        m_pMessages->insert(aux->m_szKey.ptr(),aux);
612
 
        aux->m_pQTranslation = new QString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr()));
613
 
        return *(aux->m_pQTranslation);
614
 
}
615
 
 
616
 
namespace KviLocale
617
 
{
618
 
#ifndef QT_NO_BIG_CODECS
619
 
        #define NUM_ENCODINGS 109
620
 
#else
621
 
        #define NUM_ENCODINGS 85
622
 
#endif
623
 
 
624
 
        static EncodingDescription supported_encodings[]=
625
 
        {
626
 
                { "UTF-8"                , 0 , 0 , "8-bit Unicode" },
627
 
                { "ISO-8859-1"           , 0 , 0 , "Western, Latin-1" },
628
 
                { "ISO-8859-2"           , 0 , 0 , "Central European 1" },
629
 
                { "ISO-8859-3"           , 0 , 0 , "Central European 2" },
630
 
                { "ISO-8859-4"           , 0 , 0 , "Baltic, Standard" },
631
 
                { "ISO-8859-5"           , 0 , 0 , "Cyrillic, ISO" },
632
 
                { "ISO-8859-6"           , 0 , 0 , "Arabic, Standard" },
633
 
                { "ISO-8859-7"           , 0 , 0 , "Greek" },
634
 
                { "ISO-8859-8"           , 0 , 0 , "Hebrew, visually ordered" },
635
 
                { "ISO-8859-8-i"         , 0 , 0 , "Hebrew, logically ordered" },
636
 
                { "ISO-8859-9"           , 0 , 0 , "Turkish, Latin-5" },
637
 
                { "ISO-8859-15"          , 0 , 0 , "Western, Latin-1 + Euro" },
638
 
                { "KOI8-R"               , 0 , 0 , "Cyrillic, KOI" },
639
 
                { "KOI8-U"               , 0 , 0 , "Ukrainian" },
640
 
                { "CP-1250"              , 0 , 0 , "Central European 3" },
641
 
                { "CP-1251"              , 0 , 0 , "Cyrillic, Windows" },
642
 
                { "CP-1252"              , 0 , 0 , "Western, CP" },
643
 
                { "CP-1253"              , 0 , 0 , "Greek, CP" },
644
 
                { "CP-1256"              , 0 , 0 , "Arabic, CP" },
645
 
                { "CP-1257"              , 0 , 0 , "Baltic, CP" },
646
 
                { "CP-1255"              , 0 , 0 , "Hebrew, CP" },
647
 
                { "CP-1254"              , 0 , 0 , "Turkish, CP" },
648
 
                { "TIS-620"              , 0 , 0 , "Thai" },
649
 
#ifndef QT_NO_BIG_CODECS
650
 
                { "Big5"                 , 0 , 0 , "Chinese Traditional" },
651
 
                { "Big5-HKSCS"           , 0 , 0 , "Chinese Traditional, Hong Kong" },
652
 
                { "GB18030"              , 0 , 0 , "Chinese Simplified" },
653
 
                { "JIS7"                 , 0 , 0 , "Japanese (JIS7)" },
654
 
                { "Shift-JIS"            , 0 , 0 , "Japanese (Shift-JIS)" },
655
 
                { "EUC-JP"               , 0 , 0 , "Japanese (EUC-JP)" },
656
 
                { "EUC-KR"               , 0 , 0 , "Korean" },
657
 
                { "TSCII"                , 0 , 0 , "Tamil" },
658
 
#endif
659
 
                { "ISO-8859-10"          , 0 , 0 , "ISO-8859-10" },
660
 
                { "ISO-8859-13"          , 0 , 0 , "ISO-8859-13" },
661
 
                { "ISO-8859-14"          , 0 , 0 , "ISO-8859-14" },
662
 
                { "IBM-850"              , 0 , 0 , "IBM-850" },
663
 
                { "IBM-866"              , 0 , 0 , "IBM-866" },
664
 
                { "CP874"                , 0 , 0 , "CP874" },
665
 
 
666
 
                // smart codecs that send in the local charset
667
 
                { "ISO-8859-1 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Western Latin-1, O: Western Latin-1" },
668
 
                { "ISO-8859-2 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Central European 1, O: Central European 1" },
669
 
                { "ISO-8859-3 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Central European 2, O: Central European 2" },
670
 
                { "ISO-8859-4 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Baltic, Standard, O: Baltic, Standard" },
671
 
                { "ISO-8859-5 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Cyrillic, ISO, O: Cyrillic, ISO" },
672
 
                { "ISO-8859-6 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Arabic, Standard, O: Arabic, Standard" },
673
 
                { "ISO-8859-7 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Greek, O: Greek" },
674
 
                { "ISO-8859-8 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Hebrew, visually ordered, O: Hebrew, visually ordered" },
675
 
                { "ISO-8859-8-i [UTF-8]"   , 1 , 0 , "I: 8-bit Unicode / Hebrew, logically ordered, O: Hebrew, logically ordered" },
676
 
                { "ISO-8859-9 [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Turkish, Latin-5, O: Turkish, Latin-5" },
677
 
                { "ISO-8859-15 [UTF-8]"    , 1 , 0 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: Western, Latin-1 + Euro" },
678
 
                { "KOI8-R [UTF-8]"         , 1 , 0 , "I: 8-bit Unicode / Cyrillic, KOI, O: Cyrillic, KOI" },
679
 
                { "KOI8-U [UTF-8]"         , 1 , 0 , "I: 8-bit Unicode / Ukrainian, O: Ukrainian" },
680
 
                { "CP-1250 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Central European 3, O: Central European 3" },
681
 
                { "CP-1251 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Cyrillic, Windows, O: Cyrillic, Windows" },
682
 
                { "CP-1252 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Western, CP, O: Western, CP" },
683
 
                { "CP-1253 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Greek, CP, O: Greek, CP" },
684
 
                { "CP-1256 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Arabic, CP, O: Arabic, CP" },
685
 
                { "CP-1257 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Baltic, CP, O: Baltic, CP" },
686
 
                { "CP-1255 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Hebrew, CP, O: Hebrew, CP" },
687
 
                { "CP-1254 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Turkish, CP, O: Turkish, CP" },
688
 
                { "TIS-620 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Thai, O: Thai" },
689
 
#ifndef QT_NO_BIG_CODECS
690
 
                { "Big5 [UTF-8]"           , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, O: Chinese Traditional" },
691
 
                { "Big5-HKSCS [UTF-8]"     , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: Chinese Traditional, Hong Kong" },
692
 
                { "GB18030 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / Chinese Simplified, O: Chinese Simplified" },
693
 
                { "JIS7 [UTF-8]"           , 1 , 0 , "I: 8-bit Unicode / Japanese (JIS7), O: Japanese " },
694
 
                { "Shift-JIS [UTF-8]"      , 1 , 0 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" },
695
 
                { "EUC-JP [UTF-8]"         , 1 , 0 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" },
696
 
                { "EUC-KR [UTF-8]"         , 1 , 0 , "I: 8-bit Unicode / Korean, O: Korean" },
697
 
                { "TSCII [UTF-8]"          , 1 , 0 , "I: 8-bit Unicode / Tamil, O: Tamil" },
698
 
#endif
699
 
                { "ISO-8859-10 [UTF-8]"    , 1 , 0 , "I: 8-bit Unicode / ISO-8859-10, O: ISO-8859-10" },
700
 
                { "ISO-8859-13 [UTF-8]"    , 1 , 0 , "I: 8-bit Unicode / ISO-8859-13, O: ISO-8859-13" },
701
 
                { "ISO-8859-14 [UTF-8]"    , 1 , 0 , "I: 8-bit Unicode / ISO-8859-14, O: ISO-8859-14" },
702
 
                { "IBM-850 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / IBM-850, O: IBM-850" },
703
 
                { "IBM-866 [UTF-8]"        , 1 , 0 , "I: 8-bit Unicode / IBM-866, O: IBM-866" },
704
 
                { "CP874 [UTF-8]"          , 1 , 0 , "I: 8-bit Unicode / CP874, O: CP874" },
705
 
 
706
 
                // smart codecs that send in utf8
707
 
                { "UTF-8 [ISO-8859-1]"     , 1 , 1 , "I: 8-bit Unicode / Western Latin-1, O: 8-bit Unicode" },
708
 
                { "UTF-8 [ISO-8859-2]"     , 1 , 1 , "I: 8-bit Unicode / Central European 1, O: 8-bit Unicode" },
709
 
                { "UTF-8 [ISO-8859-3]"     , 1 , 1 , "I: 8-bit Unicode / Central European 2, O: 8-bit Unicode" },
710
 
                { "UTF-8 [ISO-8859-4]"     , 1 , 1 , "I: 8-bit Unicode / Baltic, Standard, O: 8-bit Unicode" },
711
 
 
712
 
                { "UTF-8 [ISO-8859-5]"     , 1 , 1 , "I: 8-bit Unicode / Cyrillic, ISO, O: 8-bit Unicode" },
713
 
                { "UTF-8 [ISO-8859-6]"     , 1 , 1 , "I: 8-bit Unicode / Arabic, Standard, O: 8-bit Unicode" },
714
 
                { "UTF-8 [ISO-8859-7]"     , 1 , 1 , "I: 8-bit Unicode / Greek, O: 8-bit Unicode" },
715
 
                { "UTF-8 [ISO-8859-8]"     , 1 , 1 , "I: 8-bit Unicode / Hebrew, visually ordered, O: 8-bit Unicode" },
716
 
 
717
 
                { "UTF-8 [ISO-8859-8-i]"   , 1 , 1 , "I: 8-bit Unicode / Hebrew, logically ordered, O: 8-bit Unicode" },
718
 
                { "UTF-8 [ISO-8859-9]"     , 1 , 1 , "I: 8-bit Unicode / Turkish, Latin-5, O: 8-bit Unicode" },
719
 
                { "UTF-8 [ISO-8859-15]"    , 1 , 1 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: 8-bit Unicode" },
720
 
                { "UTF-8 [KOI8-R]"         , 1 , 1 , "I: 8-bit Unicode / Cyrillic, KOI, O: 8-bit Unicode" },
721
 
 
722
 
                { "UTF-8 [KOI8-U]"         , 1 , 1 , "I: 8-bit Unicode / Ukrainian, O: 8-bit Unicode" },
723
 
                { "UTF-8 [CP-1250]"        , 1 , 1 , "I: 8-bit Unicode / Central European 3, O: 8-bit Unicode" },
724
 
                { "UTF-8 [CP-1251]"        , 1 , 1 , "I: 8-bit Unicode / Cyrillic, Windows, O: 8-bit Unicode" },
725
 
                { "UTF-8 [CP-1252]"        , 1 , 1 , "I: 8-bit Unicode / Western, CP, O: 8-bit Unicode" },
726
 
 
727
 
                { "UTF-8 [CP-1253]"        , 1 , 1 , "I: 8-bit Unicode / Greek, CP, O: 8-bit Unicode" },
728
 
                { "UTF-8 [CP-1256]"        , 1 , 1 , "I: 8-bit Unicode / Arabic, CP, O: 8-bit Unicode" },
729
 
                { "UTF-8 [CP-1257]"        , 1 , 1 , "I: 8-bit Unicode / Baltic, CP, O: 8-bit Unicode" },
730
 
                { "UTF-8 [CP-1255]"        , 1 , 1 , "I: 8-bit Unicode / Hebrew, CP, O: 8-bit Unicode" },
731
 
 
732
 
                { "UTF-8 [CP-1254]"        , 1 , 1 , "I: 8-bit Unicode / Turkish, CP, O: 8-bit Unicode" },
733
 
                { "UTF-8 [TIS-620]"        , 1 , 1 , "I: 8-bit Unicode / Thai, O: 8-bit Unicode" },
734
 
#ifndef QT_NO_BIG_CODECS
735
 
                { "UTF-8 [Big5]"           , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, O: 8-bit Unicode" },
736
 
                { "UTF-8 [Big5-HKSCS]"     , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: 8-bit Unicode" },
737
 
 
738
 
                { "UTF-8 [GB18030]"        , 1 , 1 , "I: 8-bit Unicode / Chinese Simplified, O: 8-bit Unicode" },
739
 
                { "UTF-8 [JIS7]"           , 1 , 1 , "I: 8-bit Unicode / Japanese (JIS7), O: 8-bit Unicode" },
740
 
                { "UTF-8 [Shift-JIS]"      , 1 , 1 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" },
741
 
                { "UTF-8 [EUC-JP]"         , 1 , 1 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" },
742
 
 
743
 
                { "UTF-8 [EUC-KR]"         , 1 , 1 , "I: 8-bit Unicode / Korean, O: 8-bit Unicode" },
744
 
                { "UTF-8 [TSCII]"          , 1 , 1 , "I: 8-bit Unicode / Tamil, O: 8-bit Unicode" },
745
 
#endif
746
 
                { "UTF-8 [ISO-8859-10]"    , 1 , 1 , "I: 8-bit Unicode / ISO-8859-10, O: 8-bit Unicode" },
747
 
                { "UTF-8 [ISO-8859-13]"    , 1 , 1 , "I: 8-bit Unicode / ISO-8859-13, O: 8-bit Unicode" },
748
 
 
749
 
                { "UTF-8 [ISO-8859-14]"    , 1 , 1 , "I: 8-bit Unicode / ISO-8859-14, O: 8-bit Unicode" },
750
 
                { "UTF-8 [IBM-850]"        , 1 , 1 , "I: 8-bit Unicode / IBM-850, O: 8-bit Unicode" },
751
 
                { "UTF-8 [IBM-866]"        , 1 , 1 , "I: 8-bit Unicode / IBM-866, O: 8-bit Unicode" },
752
 
                { "UTF-8 [CP874]"          , 1 , 1 , "I: 8-bit Unicode / CP874, O: 8-bit Unicode" },
753
 
 
754
 
                { 0                        , 0 , 0 , 0 }
755
 
        };
756
 
 
757
 
        EncodingDescription * encodingDescription(int iIdx)
758
 
        {
759
 
                if(iIdx > NUM_ENCODINGS)return &(supported_encodings[NUM_ENCODINGS]);
760
 
                return &(supported_encodings[iIdx]);
761
 
        }
762
 
 
763
 
        QTextCodec * codecForName(const char * szName)
764
 
        {
765
 
                KviStr szTmp = szName;
766
 
                int idx = szTmp.findFirstIdx('[');
767
 
                if(idx != -1)
768
 
                {
769
 
                        // composite codec: either UTF-8 [child codec] or child codec [UTF-8]
770
 
                        KviSmartTextCodec * c = g_pSmartCodecDict->find(szName);
771
 
                        if(c)return c;
772
 
 
773
 
 
774
 
                        if(kvi_strEqualCIN("UTF-8 [",szName,7))
775
 
                        {
776
 
                                szTmp.replaceAll("UTF-8 [","");
777
 
                                szTmp.replaceAll("]","");
778
 
                                // smart codec that sends UTF-8
779
 
                                c = new KviSmartTextCodec(szName,szTmp.ptr(),true);
780
 
                        } else {
781
 
                                szTmp.cutFromFirst(' ');
782
 
                                // smart codec that sends child encoding
783
 
                                c = new KviSmartTextCodec(szName,szTmp.ptr(),false);
784
 
                        }
785
 
                        if(c->ok())
786
 
                        {
787
 
                                g_pSmartCodecDict->replace(szName,c);
788
 
                                return c;
789
 
                        } else {
790
 
                                delete c;
791
 
                        }
792
 
                }
793
 
                return QTextCodec::codecForName(szName);
794
 
        }
795
 
 
796
 
        const KviStr & localeName()
797
 
        {
798
 
                return g_szLang;
799
 
        }
800
 
 
801
 
        bool loadCatalogue(const QString &name,const QString &szLocaleDir)
802
 
        {
803
 
                //debug("Looking up catalogue %s",name);
804
 
                if(g_pCatalogueDict->find(KviQString::toUtf8(name).data()))
805
 
                        return true; // already loaded
806
 
 
807
 
                QString szBuffer;
808
 
 
809
 
                if(findCatalogue(szBuffer,name,szLocaleDir))
810
 
                {
811
 
                        KviMessageCatalogue * c = new KviMessageCatalogue();
812
 
                        if(c->load(szBuffer))
813
 
                        {
814
 
                                g_pCatalogueDict->insert(KviQString::toUtf8(name).data(),c);
815
 
                                return true;
816
 
                        }
817
 
                        delete c;
818
 
                        c = 0;
819
 
                }
820
 
                return false;
821
 
        }
822
 
 
823
 
        bool unloadCatalogue(const QString &name)
824
 
        {
825
 
                //debug("Unloading catalogue : %s",name);
826
 
                return g_pCatalogueDict->remove(KviQString::toUtf8(name).data());
827
 
        }
828
 
 
829
 
        bool findCatalogue(QString &szBuffer,const QString& name,const QString& szLocaleDir)
830
 
        {
831
 
                KviStr szLocale = g_szLang;
832
 
 
833
 
                QString szLocDir = szLocaleDir;
834
 
                KviQString::ensureLastCharIs(szLocDir,KVI_PATH_SEPARATOR_CHAR);
835
 
 
836
 
                KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
837
 
 
838
 
                if(KviFileUtils::fileExists(szBuffer))return true;
839
 
 
840
 
                if(szLocale.findFirstIdx('.') != -1)
841
 
                {
842
 
                        // things like en_GB.utf8
843
 
                        // kill them
844
 
                        szLocale.cutFromFirst('.');
845
 
 
846
 
                        KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
847
 
                        if(KviFileUtils::fileExists(szBuffer))return true;
848
 
                }
849
 
 
850
 
                if(szLocale.findFirstIdx('@') != -1)
851
 
                {
852
 
                        // things like @euro ?
853
 
                        // kill them
854
 
                        szLocale.cutFromFirst('@');
855
 
                        KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
856
 
                        if(KviFileUtils::fileExists(szBuffer))return true;
857
 
                }
858
 
 
859
 
                if(szLocale.findFirstIdx('_') != -1)
860
 
                {
861
 
                        // things like en_GB
862
 
                        // kill them
863
 
                        szLocale.cutFromFirst('_');
864
 
                        KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
865
 
                        if(KviFileUtils::fileExists(szBuffer))return true;
866
 
                }
867
 
 
868
 
                // try the lower case version too
869
 
                szLocale.toLower();
870
 
                KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
871
 
                if(KviFileUtils::fileExists(szBuffer))return true;
872
 
 
873
 
                return false;
874
 
        }
875
 
 
876
 
        //
877
 
        // This function attempts to determine the current locale
878
 
        // and then load the corresponding translation file
879
 
        // from the KVIrc locale directory
880
 
        // Returns true if the locale was correctly set
881
 
        // i.e. the locale is C or POSIX (no translation needed)
882
 
        //     or the locale is correctly defined and the
883
 
        //     translation map was sucesfully loaded
884
 
        //
885
 
 
886
 
        void init(QApplication * app,const QString &localeDir)
887
 
        {
888
 
                // first of all try to find out the current locale
889
 
                g_szLang="";
890
 
                QString szLangFile=QString("%1/.kvirc_force_locale").arg(QDir::homePath());
891
 
 
892
 
                if(KviFileUtils::fileExists(szLangFile))
893
 
                {
894
 
                        QString szTmp;
895
 
                        KviFileUtils::readFile(szLangFile,szTmp);
896
 
                        g_szLang=szTmp;
897
 
                }
898
 
                if(g_szLang.isEmpty())g_szLang = kvi_getenv("KVIRC_LANG");
899
 
                if(g_szLang.isEmpty())g_szLang = kvi_getenv("LC_MESSAGES");
900
 
                if(g_szLang.isEmpty())g_szLang = kvi_getenv("LANG");
901
 
                if(g_szLang.isEmpty())g_szLang = QLocale::system().name();
902
 
                if(g_szLang.isEmpty())g_szLang = "en";
903
 
                g_szLang.trimmed();
904
 
 
905
 
                // the main catalogue is supposed to be kvirc_<language>.mo
906
 
                g_pMainCatalogue = new KviMessageCatalogue();
907
 
                // the catalogue dict
908
 
                g_pCatalogueDict = new KviPointerHashTable<const char *,KviMessageCatalogue>;
909
 
                g_pCatalogueDict->setAutoDelete(true);
910
 
 
911
 
                // the smart codec dict
912
 
                g_pSmartCodecDict = new KviPointerHashTable<const char *,KviSmartTextCodec>;
913
 
                // the Qt docs explicitly state that we shouldn't delete
914
 
                // the codecs by ourselves...
915
 
                g_pSmartCodecDict->setAutoDelete(false);
916
 
 
917
 
                if(g_szLang.hasData())
918
 
                {
919
 
                        QString szBuffer;
920
 
                        if(findCatalogue(szBuffer,"kvirc",localeDir))
921
 
                        {
922
 
                                g_pMainCatalogue->load(szBuffer);
923
 
                                g_pTranslator = new KviTranslator(app,"kvirc_translator");
924
 
                                app->installTranslator(g_pTranslator);
925
 
                        } else {
926
 
                                KviStr szTmp = g_szLang;
927
 
                                szTmp.cutFromFirst('.');
928
 
                                szTmp.cutFromFirst('_');
929
 
                                szTmp.cutFromFirst('@');
930
 
                                szTmp.toLower();
931
 
                                if(!(kvi_strEqualCI(szTmp.ptr(),"en") ||
932
 
                                        kvi_strEqualCI(szTmp.ptr(),"c") ||
933
 
                                        kvi_strEqualCI(szTmp.ptr(),"us") ||
934
 
                                        kvi_strEqualCI(szTmp.ptr(),"gb") ||
935
 
                                        kvi_strEqualCI(szTmp.ptr(),"posix")))
936
 
                                {
937
 
                                        // FIXME: THIS IS NO LONGER VALID!!!
938
 
                                        debug("Can't find the catalogue for locale \"%s\" (%s)",g_szLang.ptr(),szTmp.ptr());
939
 
                                        debug("There is no such translation or the $LANG variable was incorrectly set");
940
 
                                        debug("You can use $KVIRC_LANG to override the catalogue name");
941
 
                                        debug("For example you can set KVIRC_LANG to it_IT to force usage of the it.mo catalogue");
942
 
                                }
943
 
                        }
944
 
                }
945
 
 
946
 
                //g_pTextCodec = QTextCodec::codecForLocale();
947
 
                //if(!g_pTextCodec)g_pTextCodec = QTextCodec::codecForLocale();
948
 
        }
949
 
 
950
 
        void done(QApplication * app)
951
 
        {
952
 
                delete g_pMainCatalogue;
953
 
                delete g_pCatalogueDict;
954
 
                delete g_pSmartCodecDict;
955
 
                g_pMainCatalogue = 0;
956
 
                g_pCatalogueDict = 0;
957
 
                g_pSmartCodecDict = 0;
958
 
                if(g_pTranslator)
959
 
                {
960
 
                        app->removeTranslator(g_pTranslator);
961
 
                        delete g_pTranslator;
962
 
            g_pTranslator = 0;
963
 
                }
964
 
        }
965
 
 
966
 
        KviMessageCatalogue * getLoadedCatalogue(const QString& name)
967
 
        {
968
 
                return g_pCatalogueDict->find(KviQString::toUtf8(name).data());
969
 
        }
970
 
 
971
 
 
972
 
        const char * translate(const char * text,const char * context)
973
 
        {
974
 
                if(context)
975
 
                {
976
 
                        KviMessageCatalogue * c = g_pCatalogueDict->find(context);
977
 
                        if(!c)
978
 
                        {
979
 
                                // FIXME: Should really try to load the catalogue here!
980
 
                                c = new KviMessageCatalogue();
981
 
                                g_pCatalogueDict->insert(context,c);
982
 
                        }
983
 
                        return c->translate(text);
984
 
                }
985
 
                return g_pMainCatalogue->translate(text);
986
 
        }
987
 
 
988
 
        const QString & translateToQString(const char * text,const char * context)
989
 
        {
990
 
                if(context)
991
 
                {
992
 
                        KviMessageCatalogue * c = g_pCatalogueDict->find(context);
993
 
                        if(!c)
994
 
                        {
995
 
                                // FIXME: Should really try to load the catalogue here!
996
 
                                c = new KviMessageCatalogue();
997
 
                                g_pCatalogueDict->insert(context,c);
998
 
                        }
999
 
                        return c->translateToQString(text);
1000
 
                }
1001
 
                return g_pMainCatalogue->translateToQString(text);
1002
 
        }
1003
 
}
1004
 
 
1005
 
KviTranslator::KviTranslator(QObject * par,const char *)
1006
 
: QTranslator(par)
1007
 
{
1008
 
}
1009
 
 
1010
 
KviTranslator::~KviTranslator()
1011
 
{
1012
 
}
1013
 
 
1014
 
QString KviTranslator::translate(const char *,const char * message,const char *) const
1015
 
{
1016
 
        // we ignore contexts and comments for qt translations
1017
 
        return g_pMainCatalogue->translateToQString(message);
1018
 
}
1019
 
 
1020
 
#if 0
1021
 
 
1022
 
// a fake table that will force these translations
1023
 
// to be included in the *.pot file
1024
 
 
1025
 
static QString fake_translations_table[]=
1026
 
{
1027
 
        // global
1028
 
        __tr2qs("OK"),
1029
 
        __tr2qs("Cancel"),
1030
 
        // color dialog
1031
 
        __tr2qs("Select color"),
1032
 
        __tr2qs("&Basic colors"),
1033
 
        __tr2qs("&Custom colors"),
1034
 
        __tr2qs("&Red"),
1035
 
        __tr2qs("&Green"),
1036
 
        __tr2qs("Bl&ue"),
1037
 
        __tr2qs("&Define Custom Colors >>"),
1038
 
        __tr2qs("&Add to Custom Colors"),
1039
 
        // font dialog
1040
 
        __tr2qs("Select Font"),
1041
 
        __tr2qs("&Font"),
1042
 
        __tr2qs("Font st&yle"),
1043
 
        __tr2qs("&Size"),
1044
 
        __tr2qs("Sample"),
1045
 
        __tr2qs("Effects"),
1046
 
        __tr2qs("Stri&keout"),
1047
 
        __tr2qs("&Underline"),
1048
 
        __tr2qs("Scr&ipt"),
1049
 
        //File selector
1050
 
        __tr2qs("Parent Directory"),
1051
 
        __tr2qs("Back"),
1052
 
        __tr2qs("Forward"),
1053
 
        __tr2qs("Reload"),
1054
 
        __tr2qs("New Directory"),
1055
 
        __tr2qs("Bookmarks"),
1056
 
        __tr2qs("Add Bookmark"),
1057
 
        __tr2qs("&Edit Bookmarks"),
1058
 
        __tr2qs("New Bookmark Folder..."),
1059
 
        __tr2qs("Configure"),
1060
 
        __tr2qs("Sorting"),
1061
 
        __tr2qs("By Name"),
1062
 
        __tr2qs("By Date"),
1063
 
        __tr2qs("By Size"),
1064
 
        __tr2qs("Reverse"),
1065
 
        __tr2qs("Directories First"),
1066
 
        __tr2qs("Case Insensitive"),
1067
 
        __tr2qs("Short View"),
1068
 
        __tr2qs("Detailed View"),
1069
 
        __tr2qs("Show Hidden Files"),
1070
 
        __tr2qs("Show Quick Access Navigation Panel"),
1071
 
        __tr2qs("Show Preview"),
1072
 
        __tr2qs("Separate Directories"),
1073
 
        __tr2qs("Often used directories"),
1074
 
        __tr2qs("Desktop"),
1075
 
        __tr2qs("Home Directory"),
1076
 
        __tr2qs("Floppy"),
1077
 
        __tr2qs("Temporary Files"),
1078
 
        __tr2qs("Network"),
1079
 
        __tr2qs("New Directory..."),
1080
 
        __tr2qs("Delete"),
1081
 
        __tr2qs("Thumbnail Previews"),
1082
 
        __tr2qs("Large Icons"),
1083
 
        __tr2qs("Small Icons"),
1084
 
        __tr2qs("Properties..."),
1085
 
        __tr2qs("&Automatic Preview"),
1086
 
        __tr2qs("&Preview"),
1087
 
        __tr2qs("&Location:"),
1088
 
        __tr2qs("&Filter:"),
1089
 
        __tr2qs("All Files"),
1090
 
        __tr2qs("&OK"),
1091
 
        __tr2qs("&Cancel")
1092
 
}
1093
 
#endif