~ubuntu-branches/ubuntu/oneiric/kdelibs/oneiric

« back to all changes in this revision

Viewing changes to .pc/kubuntu_56_langpacks_desktop_files.diff/kdecore/klocale.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2010-10-15 19:20:42 UTC
  • mfrom: (1.1.19 sid)
  • Revision ID: james.westby@ubuntu.com-20101015192042-jv1fhj33n4f5b398
Tags: 4:3.5.10.dfsg.1-5ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - make sure control and control.in are in sync
  - --with-distribution="Kubuntu (`lsb_release --codename --short`)
    $(DEB_VERSION)"
  - binary-install/kdelibs-data installs aboutkde-kubuntu.png.uu and
    cr*-device-system.png.uu
  - don't build-dep on libgamin-dev, libfam-dev
  - stop kdelibs4-dev depending on gamin/fam
  - don't install .svgz icons, docs or all_languages in kdelibs-data.install
  - rosetta support in rules common-install-prehook-impl:: [and
    common-post-build-arch:: ?] and include debian/kubuntu-desktop-i18n/
  - build-dep on: gettext-kde, kdesdk-scripts, lsb-release, base-files, sudo
  - cdbs build-dep 0.4.41ubuntu2
  - kdelibs4-dev depends on gettext-kde, kdesdk-scripts
  - copy debian/icons over
  - Make kdelibs4c2a depend on launchpad-integration, sudo.  Recommends on
    xdg-user-dirs
  - Remove 19_debianize_useragent.diff (changed to
    kubuntu_19_debianize_useragent.diff) s/Debian/Kubuntu
  - remove kdelibs4c2a depends on menu-xdg
  - include kubuntu_01_kdepot.diff and kde.pot in debian/patches/common
  - use a local copy of kde.mk without the common-install-prehook-impl::
    rule; edit debian-qt-kde.mk to include debian/cdbs/kde.mk
  - build with --with-sudo-kdesu-backend and build-dep on sudo and make
    kdelibs4c2a depend on sudo
  - kdelibs-data.install : Add nzb mimetype
  - Make kdelibs4-dev replace more recent kdelibs4c2a for overlapping files
  - remove /usr/bin/preparetips, arts files and ksvntopng from
    kdelibs4-dev.install
  - Drop the package kdelibs4-doc completely. It contained API documentation
    which is now obsolete, but still available via api.kde.org.
  - make sure control and control.in are in sync
  - in debian/rule remove .pot files outside .po directory
  - 97_automake_cleanup.diff becomes kubuntu_97_automake_cleanup.diff
  - Remove libarts1-dev from build-depends and kdelibs4-dev depends from
    control.in
* Drop kubuntu_98_fix_khc_invocation.diff, replaced by
  68_support_khelpcenter4.diff
* Drop kubuntu_97_automake_cleanup.diff, replaced by 97_automake_cleanup.diff
* Re-add security_05_XMLHttpRequest_vulnerability.diff which has been
  accidentally dropped
* Fix FTBFS, in debian/rules:
  - Add -Wl,--add-needed to LDFLAGS
  - Disable parallel building

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- c-basic-offset: 2 -*-
 
2
/* This file is part of the KDE libraries
 
3
   Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
 
4
   Copyright (c) 1999 Preston Brown <pbrown@kde.org>
 
5
   Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
 
6
   Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
 
7
 
 
8
   This library is free software; you can redistribute it and/or
 
9
   modify it under the terms of the GNU Library General Public
 
10
   License as published by the Free Software Foundation; either
 
11
   version 2 of the License, or (at your option) any later version.
 
12
 
 
13
   This library is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
   Library General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU Library General Public License
 
19
   along with this library; see the file COPYING.LIB.  If not, write to
 
20
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
21
   Boston, MA 02110-1301, USA.
 
22
*/
 
23
 
 
24
#include <config.h>
 
25
 
 
26
#include <stdlib.h> // getenv
 
27
 
 
28
#include <qtextcodec.h>
 
29
#include <qfile.h>
 
30
#include <qprinter.h>
 
31
#include <qdatetime.h>
 
32
#include <qfileinfo.h>
 
33
#include <qregexp.h>
 
34
 
 
35
#include "kcatalogue.h"
 
36
#include "kglobal.h"
 
37
#include "kstandarddirs.h"
 
38
#include "ksimpleconfig.h"
 
39
#include "kinstance.h"
 
40
#include "kconfig.h"
 
41
#include "kdebug.h"
 
42
#include "kcalendarsystem.h"
 
43
#include "kcalendarsystemfactory.h"
 
44
#include "klocale.h"
 
45
 
 
46
#ifdef Q_WS_WIN
 
47
#include <windows.h>
 
48
#endif
 
49
 
 
50
static const char * const SYSTEM_MESSAGES = "kdelibs";
 
51
 
 
52
static const char *maincatalogue = 0;
 
53
 
 
54
class KLocalePrivate
 
55
{
 
56
public:
 
57
  int weekStartDay;
 
58
  bool nounDeclension;
 
59
  bool dateMonthNamePossessive;
 
60
  QStringList languageList;
 
61
  QStringList catalogNames; // list of all catalogs (regardless of language)
 
62
  QValueList<KCatalogue> catalogues; // list of all loaded catalogs, contains one instance per catalog name and language
 
63
  QString encoding;
 
64
  QTextCodec * codecForEncoding;
 
65
  KConfig * config;
 
66
  bool formatInited;
 
67
  int /*QPrinter::PageSize*/ pageSize;
 
68
  KLocale::MeasureSystem measureSystem;
 
69
  QStringList langTwoAlpha;
 
70
  KConfig *languages;
 
71
 
 
72
  QString calendarType;
 
73
  KCalendarSystem * calendar;
 
74
  bool utf8FileEncoding;
 
75
  QString appName;
 
76
#ifdef Q_WS_WIN
 
77
  char win32SystemEncoding[3+7]; //"cp " + lang ID
 
78
#endif
 
79
};
 
80
 
 
81
static KLocale *this_klocale = 0;
 
82
 
 
83
KLocale::KLocale( const QString & catalog, KConfig * config )
 
84
{
 
85
  d = new KLocalePrivate;
 
86
  d->config = config;
 
87
  d->languages = 0;
 
88
  d->calendar = 0;
 
89
  d->formatInited = false;
 
90
 
 
91
  initEncoding(0);
 
92
  initFileNameEncoding(0);
 
93
 
 
94
  KConfig *cfg = d->config;
 
95
  this_klocale = this;
 
96
  if (!cfg) cfg = KGlobal::instance()->config();
 
97
  this_klocale = 0;
 
98
  Q_ASSERT( cfg );
 
99
 
 
100
  d->appName = catalog;
 
101
  initLanguageList( cfg, config == 0);
 
102
  initMainCatalogues(catalog);
 
103
}
 
104
 
 
105
QString KLocale::_initLanguage(KConfigBase *config)
 
106
{
 
107
  if (this_klocale)
 
108
  {
 
109
     // ### HPB Why this cast??
 
110
     this_klocale->initLanguageList((KConfig *) config, true);
 
111
     // todo: adapt current catalog list: remove unused languages, insert main catalogs, if not already found
 
112
     return this_klocale->language();
 
113
  }
 
114
  return QString::null;
 
115
}
 
116
 
 
117
void KLocale::initMainCatalogues(const QString & catalog)
 
118
{
 
119
  // Use the first non-null string.
 
120
  QString mainCatalogue = catalog;
 
121
  if (maincatalogue)
 
122
    mainCatalogue = QString::fromLatin1(maincatalogue);
 
123
 
 
124
  if (mainCatalogue.isEmpty()) {
 
125
    kdDebug(173) << "KLocale instance created called without valid "
 
126
                 << "catalog! Give an argument or call setMainCatalogue "
 
127
                 << "before init" << endl;
 
128
  }
 
129
  else {
 
130
    // do not use insertCatalogue here, that would already trigger updateCatalogs
 
131
    d->catalogNames.append( mainCatalogue );   // application catalog
 
132
    d->catalogNames.append( SYSTEM_MESSAGES ); // always include kdelibs.mo
 
133
    d->catalogNames.append( "kio" );            // always include kio.mo
 
134
    updateCatalogues(); // evaluate this for all languages
 
135
  }
 
136
}
 
137
 
 
138
void KLocale::initLanguageList(KConfig * config, bool useEnv)
 
139
{
 
140
  KConfigGroupSaver saver(config, "Locale");
 
141
 
 
142
  m_country = config->readEntry( "Country" );
 
143
  if ( m_country.isEmpty() )
 
144
    m_country = defaultCountry();
 
145
 
 
146
  // Reset the list and add the new languages
 
147
  QStringList languageList;
 
148
  if ( useEnv )
 
149
    languageList += QStringList::split
 
150
      (':', QFile::decodeName( ::getenv("KDE_LANG") ));
 
151
 
 
152
  languageList += config->readListEntry("Language", ':');
 
153
 
 
154
  // same order as setlocale use
 
155
  if ( useEnv )
 
156
    {
 
157
      // HPB: Only run splitLocale on the environment variables..
 
158
      QStringList langs;
 
159
 
 
160
      langs << QFile::decodeName( ::getenv("LC_ALL") );
 
161
      langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
 
162
      langs << QFile::decodeName( ::getenv("LANG") );
 
163
 
 
164
      for ( QStringList::Iterator it = langs.begin();
 
165
            it != langs.end();
 
166
            ++it )
 
167
        {
 
168
          QString ln, ct, chrset;
 
169
          splitLocale(*it, ln, ct, chrset);
 
170
 
 
171
          if (!ct.isEmpty()) {
 
172
            langs.insert(it, ln + '_' + ct);
 
173
            if (!chrset.isEmpty())
 
174
              langs.insert(it, ln + '_' + ct + '.' + chrset);
 
175
          }
 
176
 
 
177
          langs.insert(it, ln);
 
178
        }
 
179
 
 
180
      languageList += langs;
 
181
    }
 
182
 
 
183
  // now we have a language list -- let's use the first OK language
 
184
  setLanguage( languageList );
 
185
}
 
186
 
 
187
void KLocale::initPluralTypes()
 
188
{
 
189
  for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
 
190
    it != d->catalogues.end();
 
191
    ++it )
 
192
  {
 
193
    QString language = (*it).language();
 
194
    int pt = pluralType( language );
 
195
    (*it).setPluralType( pt );
 
196
  }
 
197
}
 
198
 
 
199
 
 
200
int KLocale::pluralType( const QString & language )
 
201
{
 
202
  for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
 
203
    it != d->catalogues.end();
 
204
    ++it )
 
205
  {
 
206
    if ( ((*it).name() == SYSTEM_MESSAGES ) && ((*it).language() == language )) {
 
207
      return pluralType( *it );
 
208
    }
 
209
  }
 
210
  // kdelibs.mo does not seem to exist for this language
 
211
  return -1;
 
212
}
 
213
 
 
214
int KLocale::pluralType( const KCatalogue& catalog )
 
215
{
 
216
    const char* pluralFormString =
 
217
    I18N_NOOP("_: Dear translator, please do not translate this string "
 
218
      "in any form, but pick the _right_ value out of "
 
219
      "NoPlural/TwoForms/French... If not sure what to do mail "
 
220
      "thd@kde.org and coolo@kde.org, they will tell you. "
 
221
      "Better leave that out if unsure, the programs will "
 
222
      "crash!!\nDefinition of PluralForm - to be set by the "
 
223
      "translator of kdelibs.po");
 
224
    QString pf (catalog.translate( pluralFormString));
 
225
    if ( pf.isEmpty() ) {
 
226
      return -1;
 
227
    }
 
228
        else if ( pf == "NoPlural" )
 
229
      return 0;
 
230
    else if ( pf == "TwoForms" )
 
231
      return 1;
 
232
    else if ( pf == "French" )
 
233
      return 2;
 
234
    else if ( pf == "OneTwoRest" )
 
235
      return 3;
 
236
    else if ( pf == "Russian" )
 
237
      return 4;
 
238
    else if ( pf == "Polish" )
 
239
      return 5;
 
240
    else if ( pf == "Slovenian" )
 
241
      return 6;
 
242
    else if ( pf == "Lithuanian" )
 
243
      return 7;
 
244
    else if ( pf == "Czech" )
 
245
      return 8;
 
246
    else if ( pf == "Slovak" )
 
247
      return 9;
 
248
    else if ( pf == "Maltese" )
 
249
      return 10;
 
250
    else if ( pf == "Arabic" )
 
251
      return 11;
 
252
    else if ( pf == "Balcan" )
 
253
      return 12;
 
254
    else if ( pf == "Macedonian" )
 
255
      return 13;
 
256
    else if ( pf == "Gaeilge" )
 
257
        return 14;
 
258
    else {
 
259
      kdWarning(173) << "Definition of PluralForm is none of "
 
260
                       << "NoPlural/"
 
261
                       << "TwoForms/"
 
262
                       << "French/"
 
263
                       << "OneTwoRest/"
 
264
                       << "Russian/"
 
265
                       << "Polish/"
 
266
                       << "Slovenian/"
 
267
                       << "Lithuanian/"
 
268
                       << "Czech/"
 
269
                       << "Slovak/"
 
270
                       << "Arabic/"
 
271
                       << "Balcan/"
 
272
               << "Macedonian/"
 
273
               << "Gaeilge/"
 
274
                       << "Maltese: " << pf << endl;
 
275
      exit(1);
 
276
    }
 
277
}
 
278
 
 
279
void KLocale::doFormatInit() const
 
280
{
 
281
  if ( d->formatInited ) return;
 
282
 
 
283
  KLocale * that = const_cast<KLocale *>(this);
 
284
  that->initFormat();
 
285
 
 
286
  d->formatInited = true;
 
287
}
 
288
 
 
289
void KLocale::initFormat()
 
290
{
 
291
  KConfig *config = d->config;
 
292
  if (!config) config = KGlobal::instance()->config();
 
293
  Q_ASSERT( config );
 
294
 
 
295
  kdDebug(173) << "KLocale::initFormat" << endl;
 
296
 
 
297
  // make sure the config files are read using the correct locale
 
298
  // ### Why not add a KConfigBase::setLocale( const KLocale * )?
 
299
  // ### Then we could remove this hack
 
300
  KLocale *lsave = KGlobal::_locale;
 
301
  KGlobal::_locale = this;
 
302
 
 
303
  KConfigGroupSaver saver(config, "Locale");
 
304
 
 
305
  KSimpleConfig entry(locate("locale",
 
306
                             QString::fromLatin1("l10n/%1/entry.desktop")
 
307
                             .arg(m_country)), true);
 
308
  entry.setGroup("KCM Locale");
 
309
 
 
310
  // Numeric
 
311
#define readConfigEntry(key, default, save) \
 
312
  save = entry.readEntry(key, QString::fromLatin1(default)); \
 
313
  save = config->readEntry(key, save);
 
314
 
 
315
#define readConfigNumEntry(key, default, save, type) \
 
316
  save = (type)entry.readNumEntry(key, default); \
 
317
  save = (type)config->readNumEntry(key, save);
 
318
 
 
319
#define readConfigBoolEntry(key, default, save) \
 
320
  save = entry.readBoolEntry(key, default); \
 
321
  save = config->readBoolEntry(key, save);
 
322
 
 
323
  readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
 
324
  readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
 
325
  m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null );
 
326
  //kdDebug(173) << "m_thousandsSeparator=" << m_thousandsSeparator << endl;
 
327
 
 
328
  readConfigEntry("PositiveSign", "", m_positiveSign);
 
329
  readConfigEntry("NegativeSign", "-", m_negativeSign);
 
330
 
 
331
  // Monetary
 
332
  readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
 
333
  readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
 
334
  readConfigEntry("MonetaryThousandsSeparator", ",",
 
335
                  m_monetaryThousandsSeparator);
 
336
  m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null);
 
337
 
 
338
  readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
 
339
  readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
 
340
                      m_positivePrefixCurrencySymbol);
 
341
  readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
 
342
                      m_negativePrefixCurrencySymbol);
 
343
  readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
 
344
                     m_positiveMonetarySignPosition, SignPosition);
 
345
  readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
 
346
                     m_negativeMonetarySignPosition, SignPosition);
 
347
 
 
348
 
 
349
  // Date and time
 
350
  readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
 
351
  readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
 
352
  readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
 
353
  readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
 
354
 
 
355
  // other
 
356
  readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
 
357
  readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
 
358
                     MeasureSystem);
 
359
  readConfigEntry("CalendarSystem", "gregorian", d->calendarType);
 
360
  delete d->calendar;
 
361
  d->calendar = 0; // ### HPB Is this the correct place?
 
362
 
 
363
  //Grammatical
 
364
  //Precedence here is l10n / i18n / config file
 
365
  KSimpleConfig language(locate("locale",
 
366
                                QString::fromLatin1("%1/entry.desktop")
 
367
                                .arg(m_language)), true);
 
368
  language.setGroup("KCM Locale");
 
369
#define read3ConfigBoolEntry(key, default, save) \
 
370
  save = entry.readBoolEntry(key, default); \
 
371
  save = language.readBoolEntry(key, save); \
 
372
  save = config->readBoolEntry(key, save);
 
373
 
 
374
  read3ConfigBoolEntry("NounDeclension", false, d->nounDeclension);
 
375
  read3ConfigBoolEntry("DateMonthNamePossessive", false,
 
376
                       d->dateMonthNamePossessive);
 
377
 
 
378
  // end of hack
 
379
  KGlobal::_locale = lsave;
 
380
}
 
381
 
 
382
bool KLocale::setCountry(const QString & country)
 
383
{
 
384
  // Check if the file exists too??
 
385
  if ( country.isEmpty() )
 
386
    return false;
 
387
 
 
388
  m_country = country;
 
389
 
 
390
  d->formatInited = false;
 
391
 
 
392
  return true;
 
393
}
 
394
 
 
395
QString KLocale::catalogueFileName(const QString & language,
 
396
                                   const KCatalogue & catalog)
 
397
{
 
398
  QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
 
399
    .arg( language )
 
400
    .arg( catalog.name() );
 
401
 
 
402
  return locate( "locale", path );
 
403
}
 
404
 
 
405
bool KLocale::setLanguage(const QString & language)
 
406
{
 
407
  if ( d->languageList.contains( language ) ) {
 
408
         d->languageList.remove( language );
 
409
  }
 
410
  d->languageList.prepend( language ); // let us consider this language to be the most important one
 
411
 
 
412
  m_language = language; // remember main language for shortcut evaluation
 
413
 
 
414
  // important when called from the outside and harmless when called before populating the
 
415
  // catalog name list
 
416
  updateCatalogues();
 
417
 
 
418
  d->formatInited = false;
 
419
 
 
420
  return true; // Maybe the mo-files for this language are empty, but in principle we can speak all languages
 
421
}
 
422
 
 
423
bool KLocale::setLanguage(const QStringList & languages)
 
424
{
 
425
  QStringList languageList( languages );
 
426
  // This list might contain
 
427
  // 1) some empty strings that we have to eliminate
 
428
  // 2) duplicate entries like in de:fr:de, where we have to keep the first occurrance of a language in order
 
429
  //    to preserve the order of precenence of the user => iterate backwards
 
430
  // 3) languages into which the application is not translated. For those languages we should not even load kdelibs.mo or kio.po.
 
431
  //    these langugage have to be dropped. Otherwise we get strange side effects, e.g. with Hebrew:
 
432
  //    the right/left switch for languages that write from
 
433
  //    right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have kdelibs.mo
 
434
  //    but nothing from appname.mo, you get a mostly English app with layout from right to left.
 
435
  //    That was considered to be a bug by the Hebrew translators.
 
436
  for( QStringList::Iterator it = languageList.fromLast();
 
437
    it != languageList.begin(); --it )
 
438
  {
 
439
    // kdDebug() << "checking " << (*it) << endl;
 
440
    bool bIsTranslated = isApplicationTranslatedInto( *it );
 
441
    if ( languageList.contains(*it) > 1 || (*it).isEmpty() || (!bIsTranslated) ) {
 
442
      // kdDebug() << "removing " << (*it) << endl;
 
443
      it = languageList.remove( it );
 
444
    }
 
445
  }
 
446
  // now this has left the first element of the list unchecked.
 
447
  // The question why this is the case is left as an exercise for the reader...
 
448
  // Besides the list might have been empty all the way, so check that too.
 
449
  if ( languageList.begin() != languageList.end() ) {
 
450
     QStringList::Iterator it = languageList.begin(); // now pointing to the first element
 
451
     // kdDebug() << "checking " << (*it) << endl;
 
452
     if( (*it).isEmpty() || !(isApplicationTranslatedInto( *it )) ) {
 
453
        // kdDebug() << "removing " << (*it) << endl;
 
454
        languageList.remove( it ); // that's what the iterator was for...
 
455
     }
 
456
  }
 
457
 
 
458
  if ( languageList.isEmpty() ) {
 
459
        // user picked no language, so we assume he/she speaks English.
 
460
        languageList.append( defaultLanguage() );
 
461
  }
 
462
  m_language = languageList.first(); // keep this for shortcut evaluations
 
463
 
 
464
  d->languageList = languageList; // keep this new list of languages to use
 
465
  d->langTwoAlpha.clear(); // Flush cache
 
466
 
 
467
  // important when called from the outside and harmless when called before populating the
 
468
  // catalog name list
 
469
  updateCatalogues();
 
470
 
 
471
  return true; // we found something. Maybe it's only English, but we found something
 
472
}
 
473
 
 
474
bool KLocale::isApplicationTranslatedInto( const QString & language)
 
475
{
 
476
  if ( language.isEmpty() ) {
 
477
    return false;
 
478
  }
 
479
 
 
480
  if ( language == defaultLanguage() ) {
 
481
    // en_us is always "installed"
 
482
    return true;
 
483
  }
 
484
 
 
485
  QString appName = d->appName;
 
486
  if (maincatalogue) {
 
487
    appName = QString::fromLatin1(maincatalogue);
 
488
  }
 
489
  // sorry, catalogueFileName requires catalog object,k which we do not have here
 
490
  // path finding was supposed to be moved completely to KCatalogue. The interface cannot
 
491
  // be changed that far during deep freeze. So in order to fix the bug now, we have
 
492
  // duplicated code for file path evaluation. Cleanup will follow later. We could have e.g.
 
493
  // a static method in KCataloge that can translate between these file names.
 
494
  // a stat
 
495
  QString sFileName = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
 
496
    .arg( language )
 
497
    .arg( appName );
 
498
  // kdDebug() << "isApplicationTranslatedInto: filename " << sFileName << endl;
 
499
 
 
500
  QString sAbsFileName = locate( "locale", sFileName );
 
501
  // kdDebug() << "isApplicationTranslatedInto: absname " << sAbsFileName << endl;
 
502
  return ! sAbsFileName.isEmpty();
 
503
}
 
504
 
 
505
void KLocale::splitLocale(const QString & aStr,
 
506
                          QString & language,
 
507
                          QString & country,
 
508
                          QString & chrset)
 
509
{
 
510
  QString str = aStr;
 
511
 
 
512
  // just in case, there is another language appended
 
513
  int f = str.find(':');
 
514
  if (f >= 0)
 
515
    str.truncate(f);
 
516
 
 
517
  country = QString::null;
 
518
  chrset = QString::null;
 
519
  language = QString::null;
 
520
 
 
521
  f = str.find('.');
 
522
  if (f >= 0)
 
523
    {
 
524
      chrset = str.mid(f + 1);
 
525
      str.truncate(f);
 
526
    }
 
527
 
 
528
  f = str.find('_');
 
529
  if (f >= 0)
 
530
    {
 
531
      country = str.mid(f + 1);
 
532
      str.truncate(f);
 
533
    }
 
534
 
 
535
  language = str;
 
536
}
 
537
 
 
538
QString KLocale::language() const
 
539
{
 
540
  return m_language;
 
541
}
 
542
 
 
543
QString KLocale::country() const
 
544
{
 
545
  return m_country;
 
546
}
 
547
 
 
548
QString KLocale::monthName(int i, bool shortName) const
 
549
{
 
550
  if ( shortName )
 
551
    switch ( i )
 
552
      {
 
553
      case 1:   return translate("January", "Jan");
 
554
      case 2:   return translate("February", "Feb");
 
555
      case 3:   return translate("March", "Mar");
 
556
      case 4:   return translate("April", "Apr");
 
557
      case 5:   return translate("May short", "May");
 
558
      case 6:   return translate("June", "Jun");
 
559
      case 7:   return translate("July", "Jul");
 
560
      case 8:   return translate("August", "Aug");
 
561
      case 9:   return translate("September", "Sep");
 
562
      case 10:  return translate("October", "Oct");
 
563
      case 11:  return translate("November", "Nov");
 
564
      case 12:  return translate("December", "Dec");
 
565
      }
 
566
  else
 
567
    switch (i)
 
568
      {
 
569
      case 1:   return translate("January");
 
570
      case 2:   return translate("February");
 
571
      case 3:   return translate("March");
 
572
      case 4:   return translate("April");
 
573
      case 5:   return translate("May long", "May");
 
574
      case 6:   return translate("June");
 
575
      case 7:   return translate("July");
 
576
      case 8:   return translate("August");
 
577
      case 9:   return translate("September");
 
578
      case 10:  return translate("October");
 
579
      case 11:  return translate("November");
 
580
      case 12:  return translate("December");
 
581
      }
 
582
 
 
583
  return QString::null;
 
584
}
 
585
 
 
586
QString KLocale::monthNamePossessive(int i, bool shortName) const
 
587
{
 
588
  if ( shortName )
 
589
    switch ( i )
 
590
      {
 
591
      case 1:   return translate("of January", "of Jan");
 
592
      case 2:   return translate("of February", "of Feb");
 
593
      case 3:   return translate("of March", "of Mar");
 
594
      case 4:   return translate("of April", "of Apr");
 
595
      case 5:   return translate("of May short", "of May");
 
596
      case 6:   return translate("of June", "of Jun");
 
597
      case 7:   return translate("of July", "of Jul");
 
598
      case 8:   return translate("of August", "of Aug");
 
599
      case 9:   return translate("of September", "of Sep");
 
600
      case 10:  return translate("of October", "of Oct");
 
601
      case 11:  return translate("of November", "of Nov");
 
602
      case 12:  return translate("of December", "of Dec");
 
603
      }
 
604
  else
 
605
    switch (i)
 
606
      {
 
607
      case 1:   return translate("of January");
 
608
      case 2:   return translate("of February");
 
609
      case 3:   return translate("of March");
 
610
      case 4:   return translate("of April");
 
611
      case 5:   return translate("of May long", "of May");
 
612
      case 6:   return translate("of June");
 
613
      case 7:   return translate("of July");
 
614
      case 8:   return translate("of August");
 
615
      case 9:   return translate("of September");
 
616
      case 10:  return translate("of October");
 
617
      case 11:  return translate("of November");
 
618
      case 12:  return translate("of December");
 
619
      }
 
620
 
 
621
  return QString::null;
 
622
}
 
623
 
 
624
QString KLocale::weekDayName (int i, bool shortName) const
 
625
{
 
626
  return calendar()->weekDayName(i, shortName);
 
627
}
 
628
 
 
629
void KLocale::insertCatalogue( const QString & catalog )
 
630
{
 
631
  if ( !d->catalogNames.contains( catalog) ) {
 
632
    d->catalogNames.append( catalog );
 
633
  }
 
634
  updateCatalogues( ); // evaluate the changed list and generate the neccessary KCatalog objects
 
635
}
 
636
 
 
637
void KLocale::updateCatalogues( )
 
638
{
 
639
  // some changes have occured. Maybe we have learned or forgotten some languages.
 
640
  // Maybe the language precedence has changed.
 
641
  // Maybe we have learned or forgotten some catalog names.
 
642
  // Now examine the list of KCatalogue objects and change it according to the new circumstances.
 
643
 
 
644
  // this could be optimized: try to reuse old KCatalog objects, but remember that the order of
 
645
  // catalogs might have changed: e.g. in this fashion
 
646
  // 1) move all catalogs into a temporary list
 
647
  // 2) iterate over all languages and catalog names
 
648
  // 3.1) pick the catalog from the saved list, if it already exists
 
649
  // 3.2) else create a new catalog.
 
650
  // but we will do this later.
 
651
 
 
652
  for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
 
653
        it != d->catalogues.end(); )
 
654
  {
 
655
     it = d->catalogues.remove(it);
 
656
  }
 
657
 
 
658
  // now iterate over all languages and all wanted catalog names and append or create them in the right order
 
659
  // the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs de/kio etc.
 
660
  // and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be in trouble with a language
 
661
  // sequende nds,en_US, de. In this case en_US must hide everything below in the language list.
 
662
  for ( QStringList::ConstIterator itLangs =  d->languageList.begin();
 
663
          itLangs != d->languageList.end(); ++itLangs)
 
664
  {
 
665
    for ( QStringList::ConstIterator itNames =  d->catalogNames.begin();
 
666
        itNames != d->catalogNames.end(); ++itNames)
 
667
    {
 
668
      KCatalogue cat( *itNames, *itLangs ); // create Catalog for this name and this language
 
669
      d->catalogues.append( cat );
 
670
        }
 
671
  }
 
672
  initPluralTypes();  // evaluate the plural type for all languages and remember this in each KCatalogue
 
673
}
 
674
 
 
675
 
 
676
 
 
677
 
 
678
void KLocale::removeCatalogue(const QString &catalog)
 
679
{
 
680
  if ( d->catalogNames.contains( catalog )) {
 
681
    d->catalogNames.remove( catalog );
 
682
    if (KGlobal::_instance)
 
683
      updateCatalogues();  // walk through the KCatalogue instances and weed out everything we no longer need
 
684
  }
 
685
}
 
686
 
 
687
void KLocale::setActiveCatalogue(const QString &catalog)
 
688
{
 
689
  if ( d->catalogNames.contains( catalog ) ) {
 
690
    d->catalogNames.remove( catalog );
 
691
        d->catalogNames.prepend( catalog );
 
692
        updateCatalogues();  // walk through the KCatalogue instances and adapt to the new order
 
693
  }
 
694
}
 
695
 
 
696
KLocale::~KLocale()
 
697
{
 
698
  delete d->calendar;
 
699
  delete d->languages;
 
700
  delete d;
 
701
  d = 0L;
 
702
}
 
703
 
 
704
QString KLocale::translate_priv(const char *msgid,
 
705
                                const char *fallback,
 
706
                                const char **translated,
 
707
                                int* pluralType ) const
 
708
{
 
709
  if ( pluralType) {
 
710
        *pluralType = -1; // unless we find something more precise
 
711
  }
 
712
  if (!msgid || !msgid[0])
 
713
    {
 
714
      kdWarning() << "KLocale: trying to look up \"\" in catalog. "
 
715
                   << "Fix the program" << endl;
 
716
      return QString::null;
 
717
    }
 
718
 
 
719
  if ( useDefaultLanguage() ) { // shortcut evaluation if en_US is main language: do not consult the catalogs
 
720
    return QString::fromUtf8( fallback );
 
721
  }
 
722
 
 
723
  for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
 
724
        it != d->catalogues.end();
 
725
        ++it )
 
726
    {
 
727
          // shortcut evaluation: once we have arrived at en_US (default language) we cannot consult
 
728
          // the catalog as it will not have an assiciated mo-file. For this default language we can
 
729
          // immediately pick the fallback string.
 
730
          if ( (*it).language() == defaultLanguage() ) {
 
731
                return QString::fromUtf8( fallback );
 
732
          }
 
733
 
 
734
      const char * text = (*it).translate( msgid );
 
735
 
 
736
      if ( text )
 
737
        {
 
738
          // we found it
 
739
          if (translated) {
 
740
            *translated = text;
 
741
          }
 
742
          if ( pluralType) {
 
743
                *pluralType = (*it).pluralType(); // remember the plural type information from the catalog that was used
 
744
          }
 
745
          return QString::fromUtf8( text );
 
746
        }
 
747
    }
 
748
 
 
749
  // Always use UTF-8 if the string was not found
 
750
  return QString::fromUtf8( fallback );
 
751
}
 
752
 
 
753
QString KLocale::translate(const char* msgid) const
 
754
{
 
755
  return translate_priv(msgid, msgid);
 
756
}
 
757
 
 
758
QString KLocale::translate( const char *index, const char *fallback) const
 
759
{
 
760
  if (!index || !index[0] || !fallback || !fallback[0])
 
761
    {
 
762
      kdDebug(173) << "KLocale: trying to look up \"\" in catalog. "
 
763
                   << "Fix the program" << endl;
 
764
      return QString::null;
 
765
    }
 
766
 
 
767
  if ( useDefaultLanguage() )
 
768
    return QString::fromUtf8( fallback );
 
769
 
 
770
  char *newstring = new char[strlen(index) + strlen(fallback) + 5];
 
771
  sprintf(newstring, "_: %s\n%s", index, fallback);
 
772
  // as copying QString is very fast, it looks slower as it is ;/
 
773
  QString r = translate_priv(newstring, fallback);
 
774
  delete [] newstring;
 
775
 
 
776
  return r;
 
777
}
 
778
 
 
779
static QString put_n_in(const QString &orig, unsigned long n)
 
780
{
 
781
  QString ret = orig;
 
782
  int index = ret.find("%n");
 
783
  if (index == -1)
 
784
    return ret;
 
785
  ret.replace(index, 2, QString::number(n));
 
786
  return ret;
 
787
}
 
788
 
 
789
#define EXPECT_LENGTH(x) \
 
790
   if (forms.count() != x) { \
 
791
      kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
 
792
      return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
 
793
 
 
794
QString KLocale::translate( const char *singular, const char *plural,
 
795
                            unsigned long n ) const
 
796
{
 
797
  if (!singular || !singular[0] || !plural || !plural[0])
 
798
    {
 
799
      kdWarning() << "KLocale: trying to look up \"\" in catalog. "
 
800
                   << "Fix the program" << endl;
 
801
      return QString::null;
 
802
    }
 
803
 
 
804
  char *newstring = new char[strlen(singular) + strlen(plural) + 6];
 
805
  sprintf(newstring, "_n: %s\n%s", singular, plural);
 
806
  // as copying QString is very fast, it looks slower as it is ;/
 
807
  int pluralType = -1;
 
808
  QString r = translate_priv(newstring, 0, 0, &pluralType);
 
809
  delete [] newstring;
 
810
 
 
811
  if ( r.isEmpty() || useDefaultLanguage() || pluralType == -1) {
 
812
    if ( n == 1 ) {
 
813
      return put_n_in( QString::fromUtf8( singular ),  n );
 
814
        } else {
 
815
          QString tmp = QString::fromUtf8( plural );
 
816
#ifndef NDEBUG
 
817
          if (tmp.find("%n") == -1) {
 
818
                          kdDebug() << "the message for i18n should contain a '%n'! " << plural << endl;
 
819
          }
 
820
#endif
 
821
      return put_n_in( tmp,  n );
 
822
        }
 
823
  }
 
824
 
 
825
  QStringList forms = QStringList::split( "\n", r, false );
 
826
  switch ( pluralType ) {
 
827
  case 0: // NoPlural
 
828
    EXPECT_LENGTH( 1 );
 
829
    return put_n_in( forms[0], n);
 
830
  case 1: // TwoForms
 
831
    EXPECT_LENGTH( 2 );
 
832
    if ( n == 1 )
 
833
      return put_n_in( forms[0], n);
 
834
    else
 
835
      return put_n_in( forms[1], n);
 
836
  case 2: // French
 
837
    EXPECT_LENGTH( 2 );
 
838
    if ( n == 1 || n == 0 )
 
839
      return put_n_in( forms[0], n);
 
840
    else
 
841
      return put_n_in( forms[1], n);
 
842
  case 3: // OneTwoRest
 
843
    EXPECT_LENGTH( 3 );
 
844
    if ( n == 1 )
 
845
      return put_n_in( forms[0], n);
 
846
    else if ( n == 2 )
 
847
      return put_n_in( forms[1], n);
 
848
    else
 
849
      return put_n_in( forms[2], n);
 
850
  case 4: // Russian, corrected by mok
 
851
    EXPECT_LENGTH( 3 );
 
852
    if ( n%10 == 1  &&  n%100 != 11)
 
853
      return put_n_in( forms[0], n); // odin fail
 
854
    else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
 
855
      return put_n_in( forms[1], n); // dva faila
 
856
    else
 
857
      return put_n_in( forms[2], n); // desyat' failov
 
858
  case 5: // Polish
 
859
    EXPECT_LENGTH( 3 );
 
860
    if ( n == 1 )
 
861
      return put_n_in( forms[0], n);
 
862
    else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
 
863
      return put_n_in( forms[1], n);
 
864
    else
 
865
      return put_n_in( forms[2], n);
 
866
  case 6: // Slovenian
 
867
    EXPECT_LENGTH( 4 );
 
868
    if ( n%100 == 1 )
 
869
      return put_n_in( forms[1], n); // ena datoteka
 
870
    else if ( n%100 == 2 )
 
871
      return put_n_in( forms[2], n); // dve datoteki
 
872
    else if ( n%100 == 3 || n%100 == 4 )
 
873
      return put_n_in( forms[3], n); // tri datoteke
 
874
    else
 
875
      return put_n_in( forms[0], n); // sto datotek
 
876
  case 7: // Lithuanian
 
877
    EXPECT_LENGTH( 3 );
 
878
    if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
 
879
      return put_n_in( forms[2], n);
 
880
    else if ( n%10 == 1 )
 
881
      return put_n_in( forms[0], n);
 
882
    else
 
883
      return put_n_in( forms[1], n);
 
884
  case 8: // Czech - use modern form which is equivalent to Slovak
 
885
  case 9: // Slovak
 
886
    EXPECT_LENGTH( 3 );
 
887
    if ( n == 1 )
 
888
      return put_n_in( forms[0], n);
 
889
    else if (( n >= 2 ) && ( n <= 4 ))
 
890
      return put_n_in( forms[1], n);
 
891
    else
 
892
      return put_n_in( forms[2], n);
 
893
  case 10: // Maltese
 
894
    EXPECT_LENGTH( 4 );
 
895
    if ( n == 1 )
 
896
      return put_n_in( forms[0], n );
 
897
    else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
 
898
      return put_n_in( forms[1], n );
 
899
    else if ( n%100 > 10 && n%100 < 20 )
 
900
      return put_n_in( forms[2], n );
 
901
    else
 
902
      return put_n_in( forms[3], n );
 
903
  case 11: // Arabic
 
904
    EXPECT_LENGTH( 4 );
 
905
    if (n == 1)
 
906
      return put_n_in(forms[0], n);
 
907
    else if (n == 2)
 
908
      return put_n_in(forms[1], n);
 
909
    else if ( n < 11)
 
910
      return put_n_in(forms[2], n);
 
911
    else
 
912
      return put_n_in(forms[3], n);
 
913
  case 12: // Balcan
 
914
     EXPECT_LENGTH( 3 );
 
915
     if (n != 11 && n % 10 == 1)
 
916
        return put_n_in(forms[0], n);
 
917
     else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
 
918
        return put_n_in(forms[1], n);
 
919
     else
 
920
        return put_n_in(forms[2], n);
 
921
  case 13: // Macedonian
 
922
     EXPECT_LENGTH(3);
 
923
     if (n % 10 == 1)
 
924
        return put_n_in(forms[0], n);
 
925
     else if (n % 10 == 2)
 
926
        return put_n_in(forms[1], n);
 
927
     else
 
928
        return put_n_in(forms[2], n);
 
929
  case 14: // Gaeilge
 
930
      EXPECT_LENGTH(5);
 
931
      if (n == 1)                       // "ceann amhain"
 
932
          return put_n_in(forms[0], n);
 
933
      else if (n == 2)                  // "dha cheann"
 
934
          return put_n_in(forms[1], n);
 
935
      else if (n < 7)                   // "%n cinn"
 
936
          return put_n_in(forms[2], n);
 
937
      else if (n < 11)                  // "%n gcinn"
 
938
          return put_n_in(forms[3], n);
 
939
      else                              // "%n ceann"
 
940
          return put_n_in(forms[4], n);
 
941
  }
 
942
  kdFatal() << "The function should have been returned in another way\n";
 
943
 
 
944
  return QString::null;
 
945
}
 
946
 
 
947
QString KLocale::translateQt( const char *context, const char *source,
 
948
                              const char *message) const
 
949
{
 
950
  if (!source || !source[0]) {
 
951
    kdWarning() << "KLocale: trying to look up \"\" in catalog. "
 
952
                << "Fix the program" << endl;
 
953
    return QString::null;
 
954
  }
 
955
 
 
956
  if ( useDefaultLanguage() ) {
 
957
    return QString::null;
 
958
  }
 
959
 
 
960
  char *newstring = 0;
 
961
  const char *translation = 0;
 
962
  QString r;
 
963
 
 
964
  if ( message && message[0]) {
 
965
    char *newstring = new char[strlen(source) + strlen(message) + 5];
 
966
    sprintf(newstring, "_: %s\n%s", source, message);
 
967
    const char *translation = 0;
 
968
    // as copying QString is very fast, it looks slower as it is ;/
 
969
    r = translate_priv(newstring, source, &translation);
 
970
    delete [] newstring;
 
971
    if (translation)
 
972
      return r;
 
973
  }
 
974
 
 
975
  if ( context && context[0] && message && message[0]) {
 
976
    newstring = new char[strlen(context) + strlen(message) + 5];
 
977
    sprintf(newstring, "_: %s\n%s", context, message);
 
978
    // as copying QString is very fast, it looks slower as it is ;/
 
979
    r = translate_priv(newstring, source, &translation);
 
980
    delete [] newstring;
 
981
    if (translation)
 
982
      return r;
 
983
  }
 
984
 
 
985
  r = translate_priv(source, source, &translation);
 
986
  if (translation)
 
987
    return r;
 
988
  return QString::null;
 
989
}
 
990
 
 
991
bool KLocale::nounDeclension() const
 
992
{
 
993
  doFormatInit();
 
994
  return d->nounDeclension;
 
995
}
 
996
 
 
997
bool KLocale::dateMonthNamePossessive() const
 
998
{
 
999
  doFormatInit();
 
1000
  return d->dateMonthNamePossessive;
 
1001
}
 
1002
 
 
1003
int KLocale::weekStartDay() const
 
1004
{
 
1005
  doFormatInit();
 
1006
  return d->weekStartDay;
 
1007
}
 
1008
 
 
1009
bool KLocale::weekStartsMonday() const //deprecated
 
1010
{
 
1011
  doFormatInit();
 
1012
  return (d->weekStartDay==1);
 
1013
}
 
1014
 
 
1015
QString KLocale::decimalSymbol() const
 
1016
{
 
1017
  doFormatInit();
 
1018
  return m_decimalSymbol;
 
1019
}
 
1020
 
 
1021
QString KLocale::thousandsSeparator() const
 
1022
{
 
1023
  doFormatInit();
 
1024
  return m_thousandsSeparator;
 
1025
}
 
1026
 
 
1027
QString KLocale::currencySymbol() const
 
1028
{
 
1029
  doFormatInit();
 
1030
  return m_currencySymbol;
 
1031
}
 
1032
 
 
1033
QString KLocale::monetaryDecimalSymbol() const
 
1034
{
 
1035
  doFormatInit();
 
1036
  return m_monetaryDecimalSymbol;
 
1037
}
 
1038
 
 
1039
QString KLocale::monetaryThousandsSeparator() const
 
1040
{
 
1041
  doFormatInit();
 
1042
  return m_monetaryThousandsSeparator;
 
1043
}
 
1044
 
 
1045
QString KLocale::positiveSign() const
 
1046
{
 
1047
  doFormatInit();
 
1048
  return m_positiveSign;
 
1049
}
 
1050
 
 
1051
QString KLocale::negativeSign() const
 
1052
{
 
1053
  doFormatInit();
 
1054
  return m_negativeSign;
 
1055
}
 
1056
 
 
1057
int KLocale::fracDigits() const
 
1058
{
 
1059
  doFormatInit();
 
1060
  return m_fracDigits;
 
1061
}
 
1062
 
 
1063
bool KLocale::positivePrefixCurrencySymbol() const
 
1064
{
 
1065
  doFormatInit();
 
1066
  return m_positivePrefixCurrencySymbol;
 
1067
}
 
1068
 
 
1069
bool KLocale::negativePrefixCurrencySymbol() const
 
1070
{
 
1071
  doFormatInit();
 
1072
  return m_negativePrefixCurrencySymbol;
 
1073
}
 
1074
 
 
1075
KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
 
1076
{
 
1077
  doFormatInit();
 
1078
  return m_positiveMonetarySignPosition;
 
1079
}
 
1080
 
 
1081
KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
 
1082
{
 
1083
  doFormatInit();
 
1084
  return m_negativeMonetarySignPosition;
 
1085
}
 
1086
 
 
1087
static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
 
1088
{
 
1089
  for ( uint l = 0; l < s.length(); l++ )
 
1090
    buffer[index++] = s.at( l );
 
1091
}
 
1092
 
 
1093
static inline void put_it_in( QChar *buffer, uint& index, int number )
 
1094
{
 
1095
  buffer[index++] = number / 10 + '0';
 
1096
  buffer[index++] = number % 10 + '0';
 
1097
}
 
1098
 
 
1099
// insert (thousands)-"separator"s into the non-fractional part of str 
 
1100
static void _insertSeparator(QString &str, const QString &separator,
 
1101
                             const QString &decimalSymbol)
 
1102
{
 
1103
  // leave fractional part untouched
 
1104
  QString mainPart = str.section(decimalSymbol, 0, 0);
 
1105
  QString fracPart = str.section(decimalSymbol, 1, 1,
 
1106
                                 QString::SectionIncludeLeadingSep);
 
1107
  
 
1108
  for (int pos = mainPart.length() - 3; pos > 0; pos -= 3)
 
1109
    mainPart.insert(pos, separator);
 
1110
 
 
1111
  str = mainPart + fracPart;
 
1112
}
 
1113
 
 
1114
QString KLocale::formatMoney(double num,
 
1115
                             const QString & symbol,
 
1116
                             int precision) const
 
1117
{
 
1118
  // some defaults
 
1119
  QString currency = symbol.isNull()
 
1120
    ? currencySymbol()
 
1121
    : symbol;
 
1122
  if (precision < 0) precision = fracDigits();
 
1123
 
 
1124
  // the number itself
 
1125
  bool neg = num < 0;
 
1126
  QString res = QString::number(neg?-num:num, 'f', precision);
 
1127
 
 
1128
  // Replace dot with locale decimal separator
 
1129
  res.replace(QChar('.'), monetaryDecimalSymbol());
 
1130
 
 
1131
  // Insert the thousand separators
 
1132
  _insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
 
1133
 
 
1134
  // set some variables we need later
 
1135
  int signpos = neg
 
1136
    ? negativeMonetarySignPosition()
 
1137
    : positiveMonetarySignPosition();
 
1138
  QString sign = neg
 
1139
    ? negativeSign()
 
1140
    : positiveSign();
 
1141
 
 
1142
  switch (signpos)
 
1143
    {
 
1144
    case ParensAround:
 
1145
      res.prepend('(');
 
1146
      res.append (')');
 
1147
      break;
 
1148
    case BeforeQuantityMoney:
 
1149
      res.prepend(sign);
 
1150
      break;
 
1151
    case AfterQuantityMoney:
 
1152
      res.append(sign);
 
1153
      break;
 
1154
    case BeforeMoney:
 
1155
      currency.prepend(sign);
 
1156
      break;
 
1157
    case AfterMoney:
 
1158
      currency.append(sign);
 
1159
      break;
 
1160
    }
 
1161
 
 
1162
  if (neg?negativePrefixCurrencySymbol():
 
1163
      positivePrefixCurrencySymbol())
 
1164
    {
 
1165
      res.prepend(' ');
 
1166
      res.prepend(currency);
 
1167
    } else {
 
1168
      res.append (' ');
 
1169
      res.append (currency);
 
1170
    }
 
1171
 
 
1172
  return res;
 
1173
}
 
1174
 
 
1175
QString KLocale::formatMoney(const QString &numStr) const
 
1176
{
 
1177
  return formatMoney(numStr.toDouble());
 
1178
}
 
1179
 
 
1180
QString KLocale::formatNumber(double num, int precision) const
 
1181
{
 
1182
  if (precision == -1) precision = 2;
 
1183
  // no need to round since QString::number does this for us
 
1184
  return formatNumber(QString::number(num, 'f', precision), false, 0);
 
1185
}
 
1186
 
 
1187
QString KLocale::formatLong(long num) const
 
1188
{
 
1189
  return formatNumber((double)num, 0);
 
1190
}
 
1191
 
 
1192
QString KLocale::formatNumber(const QString &numStr) const
 
1193
{
 
1194
  return formatNumber(numStr, true, 2);
 
1195
}
 
1196
 
 
1197
// increase the digit at 'position' by one
 
1198
static void _inc_by_one(QString &str, int position)
 
1199
{
 
1200
  for (int i = position; i >= 0; i--)
 
1201
    {
 
1202
      char last_char = str[i].latin1();
 
1203
      switch(last_char)
 
1204
        {
 
1205
        case '0':
 
1206
          str[i] = '1';
 
1207
          break;
 
1208
        case '1':
 
1209
          str[i] = '2';
 
1210
          break;
 
1211
        case '2':
 
1212
          str[i] = '3';
 
1213
          break;
 
1214
        case '3':
 
1215
          str[i] = '4';
 
1216
          break;
 
1217
        case '4':
 
1218
          str[i] = '5';
 
1219
          break;
 
1220
        case '5':
 
1221
          str[i] = '6';
 
1222
          break;
 
1223
        case '6':
 
1224
          str[i] = '7';
 
1225
          break;
 
1226
        case '7':
 
1227
          str[i] = '8';
 
1228
          break;
 
1229
        case '8':
 
1230
          str[i] = '9';
 
1231
          break;
 
1232
        case '9':
 
1233
          str[i] = '0';
 
1234
          if (i == 0) str.prepend('1');
 
1235
          continue;
 
1236
        case '.':
 
1237
          continue;
 
1238
        }
 
1239
      break;
 
1240
    }
 
1241
}
 
1242
 
 
1243
// Cut off if more digits in fractional part than 'precision'
 
1244
static void _round(QString &str, int precision)
 
1245
{
 
1246
  int decimalSymbolPos = str.find('.');
 
1247
 
 
1248
  if (decimalSymbolPos == -1)
 
1249
    if (precision == 0)  return;
 
1250
    else if (precision > 0) // add dot if missing (and needed)
 
1251
      {
 
1252
        str.append('.');
 
1253
        decimalSymbolPos = str.length() - 1;
 
1254
      }
 
1255
 
 
1256
  // fill up with more than enough zeroes (in case fractional part too short)
 
1257
  str.append(QString().fill('0', precision));
 
1258
 
 
1259
  // Now decide whether to round up or down
 
1260
  char last_char = str[decimalSymbolPos + precision + 1].latin1();
 
1261
  switch (last_char)
 
1262
    {
 
1263
    case '0':
 
1264
    case '1':
 
1265
    case '2':
 
1266
    case '3':
 
1267
    case '4':
 
1268
      // nothing to do, rounding down
 
1269
      break;
 
1270
    case '5':
 
1271
    case '6':
 
1272
    case '7':
 
1273
    case '8':
 
1274
    case '9':
 
1275
      _inc_by_one(str, decimalSymbolPos + precision);
 
1276
      break;
 
1277
    default:
 
1278
      break;
 
1279
    }
 
1280
 
 
1281
  decimalSymbolPos = str.find('.');
 
1282
  str.truncate(decimalSymbolPos + precision + 1);
 
1283
  
 
1284
  // if precision == 0 delete also '.'
 
1285
  if (precision == 0) str = str.section('.', 0, 0);
 
1286
}
 
1287
 
 
1288
QString KLocale::formatNumber(const QString &numStr, bool round,
 
1289
                              int precision) const
 
1290
{
 
1291
  QString tmpString = numStr;
 
1292
  if ((round  && precision < 0)  ||
 
1293
      ! QRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
 
1294
    return numStr;
 
1295
 
 
1296
  
 
1297
  // Skip the sign (for now)
 
1298
  bool neg = (tmpString[0] == '-');
 
1299
  if (neg  ||  tmpString[0] == '+') tmpString.remove(0, 1);
 
1300
 
 
1301
  // Split off exponential part (including 'e'-symbol)
 
1302
  QString mantString = tmpString.section('e', 0, 0,
 
1303
                                         QString::SectionCaseInsensitiveSeps);
 
1304
  QString expString = tmpString.section('e', 1, 1,
 
1305
                                        QString::SectionCaseInsensitiveSeps |
 
1306
                                        QString::SectionIncludeLeadingSep);
 
1307
 
 
1308
  if (round) _round(mantString, precision);
 
1309
 
 
1310
  // Replace dot with locale decimal separator
 
1311
  mantString.replace(QChar('.'), decimalSymbol());
 
1312
  
 
1313
  // Insert the thousand separators
 
1314
  _insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
 
1315
 
 
1316
  // How can we know where we should put the sign?
 
1317
  mantString.prepend(neg?negativeSign():positiveSign());
 
1318
  
 
1319
  return mantString +  expString;
 
1320
}
 
1321
 
 
1322
QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
 
1323
{
 
1324
  const QString rst = shortFormat?dateFormatShort():dateFormat();
 
1325
 
 
1326
  QString buffer;
 
1327
 
 
1328
  if ( ! pDate.isValid() ) return buffer;
 
1329
 
 
1330
  bool escape = false;
 
1331
 
 
1332
  int year = calendar()->year(pDate);
 
1333
  int month = calendar()->month(pDate);
 
1334
 
 
1335
  for ( uint format_index = 0; format_index < rst.length(); ++format_index )
 
1336
    {
 
1337
      if ( !escape )
 
1338
        {
 
1339
          if ( rst.at( format_index ).unicode() == '%' )
 
1340
            escape = true;
 
1341
          else
 
1342
            buffer.append(rst.at(format_index));
 
1343
        }
 
1344
      else
 
1345
        {
 
1346
          switch ( rst.at( format_index ).unicode() )
 
1347
            {
 
1348
            case '%':
 
1349
              buffer.append('%');
 
1350
              break;
 
1351
            case 'Y':
 
1352
              buffer.append(calendar()->yearString(pDate, false));
 
1353
              break;
 
1354
            case 'y':
 
1355
              buffer.append(calendar()->yearString(pDate, true));
 
1356
              break;
 
1357
            case 'n':
 
1358
              buffer.append(calendar()->monthString(pDate, true));
 
1359
              break;
 
1360
            case 'e':
 
1361
              buffer.append(calendar()->dayString(pDate, true));
 
1362
              break;
 
1363
            case 'm':
 
1364
              buffer.append(calendar()->monthString(pDate, false));
 
1365
              break;
 
1366
            case 'b':
 
1367
              if (d->nounDeclension && d->dateMonthNamePossessive)
 
1368
                buffer.append(calendar()->monthNamePossessive(month, year, true));
 
1369
              else
 
1370
                buffer.append(calendar()->monthName(month, year, true));
 
1371
              break;
 
1372
            case 'B':
 
1373
              if (d->nounDeclension && d->dateMonthNamePossessive)
 
1374
                buffer.append(calendar()->monthNamePossessive(month, year, false));
 
1375
              else
 
1376
                buffer.append(calendar()->monthName(month, year, false));
 
1377
              break;
 
1378
            case 'd':
 
1379
              buffer.append(calendar()->dayString(pDate, false));
 
1380
              break;
 
1381
            case 'a':
 
1382
              buffer.append(calendar()->weekDayName(pDate, true));
 
1383
              break;
 
1384
            case 'A':
 
1385
              buffer.append(calendar()->weekDayName(pDate, false));
 
1386
              break;
 
1387
            default:
 
1388
              buffer.append(rst.at(format_index));
 
1389
              break;
 
1390
            }
 
1391
          escape = false;
 
1392
        }
 
1393
    }
 
1394
  return buffer;
 
1395
}
 
1396
 
 
1397
void KLocale::setMainCatalogue(const char *catalog)
 
1398
{
 
1399
  maincatalogue = catalog;
 
1400
}
 
1401
 
 
1402
double KLocale::readNumber(const QString &_str, bool * ok) const
 
1403
{
 
1404
  QString str = _str.stripWhiteSpace();
 
1405
  bool neg = str.find(negativeSign()) == 0;
 
1406
  if (neg)
 
1407
    str.remove( 0, negativeSign().length() );
 
1408
 
 
1409
  /* will hold the scientific notation portion of the number.
 
1410
     Example, with 2.34E+23, exponentialPart == "E+23"
 
1411
  */
 
1412
  QString exponentialPart;
 
1413
  int EPos;
 
1414
 
 
1415
  EPos = str.find('E', 0, false);
 
1416
 
 
1417
  if (EPos != -1)
 
1418
  {
 
1419
    exponentialPart = str.mid(EPos);
 
1420
    str = str.left(EPos);
 
1421
  }
 
1422
 
 
1423
  int pos = str.find(decimalSymbol());
 
1424
  QString major;
 
1425
  QString minor;
 
1426
  if ( pos == -1 )
 
1427
    major = str;
 
1428
  else
 
1429
    {
 
1430
      major = str.left(pos);
 
1431
      minor = str.mid(pos + decimalSymbol().length());
 
1432
    }
 
1433
 
 
1434
  // Remove thousand separators
 
1435
  int thlen = thousandsSeparator().length();
 
1436
  int lastpos = 0;
 
1437
  while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
 
1438
  {
 
1439
    // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
 
1440
    int fromEnd = major.length() - pos;
 
1441
    if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
 
1442
        || pos - lastpos > 3 // More than 3 digits between two separators -> error
 
1443
        || pos == 0          // Can't start with a separator
 
1444
        || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
 
1445
    {
 
1446
      if (ok) *ok = false;
 
1447
      return 0.0;
 
1448
    }
 
1449
 
 
1450
    lastpos = pos;
 
1451
    major.remove( pos, thlen );
 
1452
  }
 
1453
  if (lastpos>0 && major.length()-lastpos!=3)   // Must have exactly 3 digits after the last separator
 
1454
  {
 
1455
    if (ok) *ok = false;
 
1456
    return 0.0;
 
1457
  }
 
1458
 
 
1459
  QString tot;
 
1460
  if (neg) tot = '-';
 
1461
 
 
1462
  tot += major + '.' + minor + exponentialPart;
 
1463
 
 
1464
  return tot.toDouble(ok);
 
1465
}
 
1466
 
 
1467
double KLocale::readMoney(const QString &_str, bool * ok) const
 
1468
{
 
1469
  QString str = _str.stripWhiteSpace();
 
1470
  bool neg = false;
 
1471
  bool currencyFound = false;
 
1472
  QString symbol = currencySymbol();
 
1473
  // First try removing currency symbol from either end
 
1474
  int pos = str.find(symbol);
 
1475
  if ( pos == 0 || pos == (int) str.length()-symbol.length() )
 
1476
    {
 
1477
      str.remove(pos,symbol.length());
 
1478
      str = str.stripWhiteSpace();
 
1479
      currencyFound = true;
 
1480
    }
 
1481
  if (str.isEmpty())
 
1482
    {
 
1483
      if (ok) *ok = false;
 
1484
      return 0;
 
1485
    }
 
1486
  // Then try removing negative sign from either end
 
1487
  // (with a special case for parenthesis)
 
1488
  if (negativeMonetarySignPosition() == ParensAround)
 
1489
    {
 
1490
      if (str[0] == '(' && str[str.length()-1] == ')')
 
1491
        {
 
1492
          neg = true;
 
1493
          str.remove(str.length()-1,1);
 
1494
          str.remove(0,1);
 
1495
        }
 
1496
    }
 
1497
  else
 
1498
    {
 
1499
      int i1 = str.find(negativeSign());
 
1500
      if ( i1 == 0 || i1 == (int) str.length()-1 )
 
1501
        {
 
1502
          neg = true;
 
1503
          str.remove(i1,negativeSign().length());
 
1504
        }
 
1505
    }
 
1506
  if (neg) str = str.stripWhiteSpace();
 
1507
 
 
1508
  // Finally try again for the currency symbol, if we didn't find
 
1509
  // it already (because of the negative sign being in the way).
 
1510
  if ( !currencyFound )
 
1511
    {
 
1512
      pos = str.find(symbol);
 
1513
      if ( pos == 0 || pos == (int) str.length()-symbol.length() )
 
1514
        {
 
1515
          str.remove(pos,symbol.length());
 
1516
          str = str.stripWhiteSpace();
 
1517
        }
 
1518
    }
 
1519
 
 
1520
  // And parse the rest as a number
 
1521
  pos = str.find(monetaryDecimalSymbol());
 
1522
  QString major;
 
1523
  QString minior;
 
1524
  if (pos == -1)
 
1525
    major = str;
 
1526
  else
 
1527
    {
 
1528
      major = str.left(pos);
 
1529
      minior = str.mid(pos + monetaryDecimalSymbol().length());
 
1530
    }
 
1531
 
 
1532
  // Remove thousand separators
 
1533
  int thlen = monetaryThousandsSeparator().length();
 
1534
  int lastpos = 0;
 
1535
  while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
 
1536
  {
 
1537
    // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
 
1538
    int fromEnd = major.length() - pos;
 
1539
    if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
 
1540
        || pos - lastpos > 3 // More than 3 digits between two separators -> error
 
1541
        || pos == 0          // Can't start with a separator
 
1542
        || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
 
1543
    {
 
1544
      if (ok) *ok = false;
 
1545
      return 0.0;
 
1546
    }
 
1547
    lastpos = pos;
 
1548
    major.remove( pos, thlen );
 
1549
  }
 
1550
  if (lastpos>0 && major.length()-lastpos!=3)   // Must have exactly 3 digits after the last separator
 
1551
  {
 
1552
    if (ok) *ok = false;
 
1553
    return 0.0;
 
1554
  }
 
1555
 
 
1556
  QString tot;
 
1557
  if (neg) tot = '-';
 
1558
  tot += major + '.' + minior;
 
1559
  return tot.toDouble(ok);
 
1560
}
 
1561
 
 
1562
/**
 
1563
 * helper function to read integers
 
1564
 * @param str
 
1565
 * @param pos the position to start at. It will be updated when we parse it.
 
1566
 * @return the integer read in the string, or -1 if no string
 
1567
 */
 
1568
static int readInt(const QString &str, uint &pos)
 
1569
{
 
1570
  if (!str.at(pos).isDigit()) return -1;
 
1571
  int result = 0;
 
1572
  for (; str.length() > pos && str.at(pos).isDigit(); pos++)
 
1573
    {
 
1574
      result *= 10;
 
1575
      result += str.at(pos).digitValue();
 
1576
    }
 
1577
 
 
1578
  return result;
 
1579
}
 
1580
 
 
1581
QDate KLocale::readDate(const QString &intstr, bool* ok) const
 
1582
{
 
1583
  QDate date;
 
1584
  date = readDate(intstr, ShortFormat, ok);
 
1585
  if (date.isValid()) return date;
 
1586
  return readDate(intstr, NormalFormat, ok);
 
1587
}
 
1588
 
 
1589
QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
 
1590
{
 
1591
  QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
 
1592
  return readDate( intstr, fmt, ok );
 
1593
}
 
1594
 
 
1595
QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
 
1596
{
 
1597
  //kdDebug() << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl;
 
1598
  QString str = intstr.simplifyWhiteSpace().lower();
 
1599
  int day = -1, month = -1;
 
1600
  // allow the year to be omitted if not in the format
 
1601
  int year = calendar()->year(QDate::currentDate());
 
1602
  uint strpos = 0;
 
1603
  uint fmtpos = 0;
 
1604
 
 
1605
  int iLength; // Temporary variable used when reading input
 
1606
 
 
1607
  bool error = false;
 
1608
 
 
1609
  while (fmt.length() > fmtpos && str.length() > strpos && !error)
 
1610
  {
 
1611
 
 
1612
    QChar c = fmt.at(fmtpos++);
 
1613
 
 
1614
    if (c != '%') {
 
1615
      if (c.isSpace() && str.at(strpos).isSpace())
 
1616
        strpos++;
 
1617
      else if (c != str.at(strpos++))
 
1618
        error = true;
 
1619
    }
 
1620
    else
 
1621
    {
 
1622
      int j;
 
1623
      // remove space at the beginning
 
1624
      if (str.length() > strpos && str.at(strpos).isSpace())
 
1625
        strpos++;
 
1626
 
 
1627
      c = fmt.at(fmtpos++);
 
1628
      switch (c)
 
1629
      {
 
1630
        case 'a':
 
1631
        case 'A':
 
1632
 
 
1633
          error = true;
 
1634
          j = 1;
 
1635
          while (error && (j < 8)) {
 
1636
            QString s = calendar()->weekDayName(j, c == 'a').lower();
 
1637
            int len = s.length();
 
1638
            if (str.mid(strpos, len) == s)
 
1639
            {
 
1640
              strpos += len;
 
1641
              error = false;
 
1642
            }
 
1643
            j++;
 
1644
          }
 
1645
          break;
 
1646
        case 'b':
 
1647
        case 'B':
 
1648
 
 
1649
          error = true;
 
1650
          if (d->nounDeclension && d->dateMonthNamePossessive) {
 
1651
            j = 1;
 
1652
            while (error && (j < 13)) {
 
1653
              QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower();
 
1654
              int len = s.length();
 
1655
              if (str.mid(strpos, len) == s) {
 
1656
                month = j;
 
1657
                strpos += len;
 
1658
                error = false;
 
1659
              }
 
1660
              j++;
 
1661
            }
 
1662
          }
 
1663
          j = 1;
 
1664
          while (error && (j < 13)) {
 
1665
            QString s = calendar()->monthName(j, year, c == 'b').lower();
 
1666
            int len = s.length();
 
1667
            if (str.mid(strpos, len) == s) {
 
1668
              month = j;
 
1669
              strpos += len;
 
1670
              error = false;
 
1671
            }
 
1672
            j++;
 
1673
          }
 
1674
          break;
 
1675
        case 'd':
 
1676
        case 'e':
 
1677
          day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
 
1678
          strpos += iLength;
 
1679
 
 
1680
          error = iLength <= 0;
 
1681
          break;
 
1682
 
 
1683
        case 'n':
 
1684
        case 'm':
 
1685
          month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
 
1686
          strpos += iLength;
 
1687
 
 
1688
          error = iLength <= 0;
 
1689
          break;
 
1690
 
 
1691
        case 'Y':
 
1692
        case 'y':
 
1693
          year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
 
1694
          strpos += iLength;
 
1695
 
 
1696
          error = iLength <= 0;
 
1697
          break;
 
1698
      }
 
1699
    }
 
1700
  }
 
1701
 
 
1702
  /* for a match, we should reach the end of both strings, not just one of
 
1703
     them */
 
1704
  if ( fmt.length() > fmtpos || str.length() > strpos )
 
1705
  {
 
1706
    error = true;
 
1707
  }
 
1708
 
 
1709
  //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl;
 
1710
  if ( year != -1 && month != -1 && day != -1 && !error)
 
1711
  {
 
1712
    if (ok) *ok = true;
 
1713
 
 
1714
    QDate result;
 
1715
    calendar()->setYMD(result, year, month, day);
 
1716
 
 
1717
    return result;
 
1718
  }
 
1719
  else
 
1720
  {
 
1721
    if (ok) *ok = false;
 
1722
    return QDate(); // invalid date
 
1723
  }
 
1724
}
 
1725
 
 
1726
QTime KLocale::readTime(const QString &intstr, bool *ok) const
 
1727
{
 
1728
  QTime _time;
 
1729
  _time = readTime(intstr, WithSeconds, ok);
 
1730
  if (_time.isValid()) return _time;
 
1731
  return readTime(intstr, WithoutSeconds, ok);
 
1732
}
 
1733
 
 
1734
QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
 
1735
{
 
1736
  QString str = intstr.simplifyWhiteSpace().lower();
 
1737
  QString Format = timeFormat().simplifyWhiteSpace();
 
1738
  if (flags & WithoutSeconds)
 
1739
    Format.remove(QRegExp(".%S"));
 
1740
 
 
1741
  int hour = -1, minute = -1;
 
1742
  int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0; // don't require seconds
 
1743
  bool g_12h = false;
 
1744
  bool pm = false;
 
1745
  uint strpos = 0;
 
1746
  uint Formatpos = 0;
 
1747
 
 
1748
  while (Format.length() > Formatpos || str.length() > strpos)
 
1749
    {
 
1750
      if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
 
1751
 
 
1752
      QChar c = Format.at(Formatpos++);
 
1753
 
 
1754
      if (c != '%')
 
1755
        {
 
1756
          if (c.isSpace())
 
1757
            strpos++;
 
1758
          else if (c != str.at(strpos++))
 
1759
            goto error;
 
1760
          continue;
 
1761
        }
 
1762
 
 
1763
      // remove space at the beginning
 
1764
      if (str.length() > strpos && str.at(strpos).isSpace())
 
1765
        strpos++;
 
1766
 
 
1767
      c = Format.at(Formatpos++);
 
1768
      switch (c)
 
1769
        {
 
1770
        case 'p':
 
1771
          {
 
1772
            QString s;
 
1773
            s = translate("pm").lower();
 
1774
            int len = s.length();
 
1775
            if (str.mid(strpos, len) == s)
 
1776
              {
 
1777
                pm = true;
 
1778
                strpos += len;
 
1779
              }
 
1780
            else
 
1781
              {
 
1782
                s = translate("am").lower();
 
1783
                len = s.length();
 
1784
                if (str.mid(strpos, len) == s) {
 
1785
                  pm = false;
 
1786
                  strpos += len;
 
1787
                }
 
1788
                else
 
1789
                  goto error;
 
1790
              }
 
1791
          }
 
1792
          break;
 
1793
 
 
1794
        case 'k':
 
1795
        case 'H':
 
1796
          g_12h = false;
 
1797
          hour = readInt(str, strpos);
 
1798
          if (hour < 0 || hour > 23)
 
1799
            goto error;
 
1800
 
 
1801
          break;
 
1802
 
 
1803
        case 'l':
 
1804
        case 'I':
 
1805
          g_12h = true;
 
1806
          hour = readInt(str, strpos);
 
1807
          if (hour < 1 || hour > 12)
 
1808
            goto error;
 
1809
 
 
1810
          break;
 
1811
 
 
1812
        case 'M':
 
1813
          minute = readInt(str, strpos);
 
1814
          if (minute < 0 || minute > 59)
 
1815
            goto error;
 
1816
 
 
1817
          break;
 
1818
 
 
1819
        case 'S':
 
1820
          second = readInt(str, strpos);
 
1821
          if (second < 0 || second > 59)
 
1822
            goto error;
 
1823
 
 
1824
          break;
 
1825
        }
 
1826
    }
 
1827
  if (g_12h) {
 
1828
    hour %= 12;
 
1829
    if (pm) hour += 12;
 
1830
  }
 
1831
 
 
1832
  if (ok) *ok = true;
 
1833
  return QTime(hour, minute, second);
 
1834
 
 
1835
 error:
 
1836
  if (ok) *ok = false;
 
1837
  // ######## KDE4: remove this
 
1838
  return QTime(-1, -1, -1); // return invalid date if it didn't work
 
1839
}
 
1840
 
 
1841
//BIC: merge with below
 
1842
QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
 
1843
{
 
1844
  return formatTime( pTime, includeSecs, false );
 
1845
}
 
1846
 
 
1847
QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
 
1848
{
 
1849
  const QString rst = timeFormat();
 
1850
 
 
1851
  // only "pm/am" here can grow, the rest shrinks, but
 
1852
  // I'm rather safe than sorry
 
1853
  QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
 
1854
 
 
1855
  uint index = 0;
 
1856
  bool escape = false;
 
1857
  int number = 0;
 
1858
 
 
1859
  for ( uint format_index = 0; format_index < rst.length(); format_index++ )
 
1860
    {
 
1861
      if ( !escape )
 
1862
        {
 
1863
          if ( rst.at( format_index ).unicode() == '%' )
 
1864
            escape = true;
 
1865
          else
 
1866
            buffer[index++] = rst.at( format_index );
 
1867
        }
 
1868
      else
 
1869
        {
 
1870
          switch ( rst.at( format_index ).unicode() )
 
1871
            {
 
1872
            case '%':
 
1873
              buffer[index++] = '%';
 
1874
              break;
 
1875
            case 'H':
 
1876
              put_it_in( buffer, index, pTime.hour() );
 
1877
              break;
 
1878
            case 'I':
 
1879
              if ( isDuration )
 
1880
                  put_it_in( buffer, index, pTime.hour() );
 
1881
              else
 
1882
                  put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
 
1883
              break;
 
1884
            case 'M':
 
1885
              put_it_in( buffer, index, pTime.minute() );
 
1886
              break;
 
1887
            case 'S':
 
1888
              if (includeSecs)
 
1889
                put_it_in( buffer, index, pTime.second() );
 
1890
              else if ( index > 0 )
 
1891
                {
 
1892
                  // we remove the separator sign before the seconds and
 
1893
                  // assume that works everywhere
 
1894
                  --index;
 
1895
                  break;
 
1896
                }
 
1897
              break;
 
1898
            case 'k':
 
1899
              number = pTime.hour();
 
1900
            case 'l':
 
1901
              // to share the code
 
1902
              if ( rst.at( format_index ).unicode() == 'l' )
 
1903
                number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
 
1904
              if ( number / 10 )
 
1905
                buffer[index++] = number / 10 + '0';
 
1906
              buffer[index++] = number % 10 + '0';
 
1907
              break;
 
1908
            case 'p':
 
1909
              if ( !isDuration )
 
1910
              {
 
1911
                QString s;
 
1912
                if ( pTime.hour() >= 12 )
 
1913
                  put_it_in( buffer, index, translate("pm") );
 
1914
                else
 
1915
                  put_it_in( buffer, index, translate("am") );
 
1916
              }
 
1917
              break;
 
1918
            default:
 
1919
              buffer[index++] = rst.at( format_index );
 
1920
              break;
 
1921
            }
 
1922
          escape = false;
 
1923
        }
 
1924
    }
 
1925
  QString ret( buffer, index );
 
1926
  delete [] buffer;
 
1927
  if ( isDuration ) // eliminate trailing-space due to " %p"
 
1928
    return ret.stripWhiteSpace();
 
1929
  else
 
1930
    return ret;
 
1931
}
 
1932
 
 
1933
bool KLocale::use12Clock() const
 
1934
{
 
1935
  if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
 
1936
      (timeFormat().contains(QString::fromLatin1("%l")) > 0))
 
1937
    return true;
 
1938
  else
 
1939
    return false;
 
1940
}
 
1941
 
 
1942
QString KLocale::languages() const
 
1943
{
 
1944
  return d->languageList.join( QString::fromLatin1(":") );
 
1945
}
 
1946
 
 
1947
QStringList KLocale::languageList() const
 
1948
{
 
1949
  return d->languageList;
 
1950
}
 
1951
 
 
1952
QString KLocale::formatDateTime(const QDateTime &pDateTime,
 
1953
                                bool shortFormat,
 
1954
                                bool includeSeconds) const
 
1955
{
 
1956
  return translate("concatenation of dates and time", "%1 %2")
 
1957
    .arg( formatDate( pDateTime.date(), shortFormat ) )
 
1958
    .arg( formatTime( pDateTime.time(), includeSeconds ) );
 
1959
}
 
1960
 
 
1961
QString i18n(const char* text)
 
1962
{
 
1963
  register KLocale *instance = KGlobal::locale();
 
1964
  if (instance)
 
1965
    return instance->translate(text);
 
1966
  return QString::fromUtf8(text);
 
1967
}
 
1968
 
 
1969
QString i18n(const char* index, const char *text)
 
1970
{
 
1971
  register KLocale *instance = KGlobal::locale();
 
1972
  if (instance)
 
1973
    return instance->translate(index, text);
 
1974
  return QString::fromUtf8(text);
 
1975
}
 
1976
 
 
1977
QString i18n(const char* singular, const char* plural, unsigned long n)
 
1978
{
 
1979
  register KLocale *instance = KGlobal::locale();
 
1980
  if (instance)
 
1981
    return instance->translate(singular, plural, n);
 
1982
  if (n == 1)
 
1983
    return put_n_in(QString::fromUtf8(singular), n);
 
1984
  else
 
1985
    return put_n_in(QString::fromUtf8(plural), n);
 
1986
}
 
1987
 
 
1988
void KLocale::initInstance()
 
1989
{
 
1990
  if (KGlobal::_locale)
 
1991
    return;
 
1992
 
 
1993
  KInstance *app = KGlobal::instance();
 
1994
  if (app) {
 
1995
    KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
 
1996
 
 
1997
    // only do this for the global instance
 
1998
    QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
 
1999
  }
 
2000
  else
 
2001
    kdDebug(173) << "no app name available using KLocale - nothing to do\n";
 
2002
}
 
2003
 
 
2004
QString KLocale::langLookup(const QString &fname, const char *rtype)
 
2005
{
 
2006
  QStringList search;
 
2007
 
 
2008
  // assemble the local search paths
 
2009
  const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
 
2010
 
 
2011
  // look up the different languages
 
2012
  for (int id=localDoc.count()-1; id >= 0; --id)
 
2013
    {
 
2014
      QStringList langs = KGlobal::locale()->languageList();
 
2015
      langs.append( "en" );
 
2016
      langs.remove( defaultLanguage() );
 
2017
      QStringList::ConstIterator lang;
 
2018
      for (lang = langs.begin(); lang != langs.end(); ++lang)
 
2019
        search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
 
2020
    }
 
2021
 
 
2022
  // try to locate the file
 
2023
  QStringList::Iterator it;
 
2024
  for (it = search.begin(); it != search.end(); ++it)
 
2025
    {
 
2026
      kdDebug(173) << "Looking for help in: " << *it << endl;
 
2027
 
 
2028
      QFileInfo info(*it);
 
2029
      if (info.exists() && info.isFile() && info.isReadable())
 
2030
        return *it;
 
2031
    }
 
2032
 
 
2033
  return QString::null;
 
2034
}
 
2035
 
 
2036
bool KLocale::useDefaultLanguage() const
 
2037
{
 
2038
  return language() == defaultLanguage();
 
2039
}
 
2040
 
 
2041
void KLocale::initEncoding(KConfig *)
 
2042
{
 
2043
  const int mibDefault = 4; // ISO 8859-1
 
2044
 
 
2045
  // This all made more sense when we still had the EncodingEnum config key.
 
2046
  setEncoding( QTextCodec::codecForLocale()->mibEnum() );
 
2047
 
 
2048
  if ( !d->codecForEncoding )
 
2049
    {
 
2050
      kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
 
2051
      setEncoding(mibDefault);
 
2052
    }
 
2053
 
 
2054
  Q_ASSERT( d->codecForEncoding );
 
2055
}
 
2056
 
 
2057
void KLocale::initFileNameEncoding(KConfig *)
 
2058
{
 
2059
  // If the following environment variable is set, assume all filenames
 
2060
  // are in UTF-8 regardless of the current C locale.
 
2061
  d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0;
 
2062
  if (d->utf8FileEncoding)
 
2063
  {
 
2064
    QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
 
2065
    QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
 
2066
  }
 
2067
  // Otherwise, stay with QFile's default filename encoding functions
 
2068
  // which, on Unix platforms, use the locale's codec.
 
2069
}
 
2070
 
 
2071
QCString KLocale::encodeFileNameUTF8( const QString & fileName )
 
2072
{
 
2073
  return fileName.utf8();
 
2074
}
 
2075
 
 
2076
QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
 
2077
{
 
2078
  return QString::fromUtf8(localFileName);
 
2079
}
 
2080
 
 
2081
void KLocale::setDateFormat(const QString & format)
 
2082
{
 
2083
  doFormatInit();
 
2084
  m_dateFormat = format.stripWhiteSpace();
 
2085
}
 
2086
 
 
2087
void KLocale::setDateFormatShort(const QString & format)
 
2088
{
 
2089
  doFormatInit();
 
2090
  m_dateFormatShort = format.stripWhiteSpace();
 
2091
}
 
2092
 
 
2093
void KLocale::setDateMonthNamePossessive(bool possessive)
 
2094
{
 
2095
  doFormatInit();
 
2096
  d->dateMonthNamePossessive = possessive;
 
2097
}
 
2098
 
 
2099
void KLocale::setTimeFormat(const QString & format)
 
2100
{
 
2101
  doFormatInit();
 
2102
  m_timeFormat = format.stripWhiteSpace();
 
2103
}
 
2104
 
 
2105
void KLocale::setWeekStartsMonday(bool start) //deprecated
 
2106
{
 
2107
  doFormatInit();
 
2108
  if (start)
 
2109
    d->weekStartDay = 1;
 
2110
  else
 
2111
    d->weekStartDay = 7;
 
2112
}
 
2113
 
 
2114
void KLocale::setWeekStartDay(int day)
 
2115
{
 
2116
  doFormatInit();
 
2117
  if (day>7 || day<1)
 
2118
    d->weekStartDay = 1; //Monday is default
 
2119
  else
 
2120
    d->weekStartDay = day;
 
2121
}
 
2122
 
 
2123
QString KLocale::dateFormat() const
 
2124
{
 
2125
  doFormatInit();
 
2126
  return m_dateFormat;
 
2127
}
 
2128
 
 
2129
QString KLocale::dateFormatShort() const
 
2130
{
 
2131
  doFormatInit();
 
2132
  return m_dateFormatShort;
 
2133
}
 
2134
 
 
2135
QString KLocale::timeFormat() const
 
2136
{
 
2137
  doFormatInit();
 
2138
  return m_timeFormat;
 
2139
}
 
2140
 
 
2141
void KLocale::setDecimalSymbol(const QString & symbol)
 
2142
{
 
2143
  doFormatInit();
 
2144
  m_decimalSymbol = symbol.stripWhiteSpace();
 
2145
}
 
2146
 
 
2147
void KLocale::setThousandsSeparator(const QString & separator)
 
2148
{
 
2149
  doFormatInit();
 
2150
  // allow spaces here
 
2151
  m_thousandsSeparator = separator;
 
2152
}
 
2153
 
 
2154
void KLocale::setPositiveSign(const QString & sign)
 
2155
{
 
2156
  doFormatInit();
 
2157
  m_positiveSign = sign.stripWhiteSpace();
 
2158
}
 
2159
 
 
2160
void KLocale::setNegativeSign(const QString & sign)
 
2161
{
 
2162
  doFormatInit();
 
2163
  m_negativeSign = sign.stripWhiteSpace();
 
2164
}
 
2165
 
 
2166
void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
 
2167
{
 
2168
  doFormatInit();
 
2169
  m_positiveMonetarySignPosition = signpos;
 
2170
}
 
2171
 
 
2172
void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
 
2173
{
 
2174
  doFormatInit();
 
2175
  m_negativeMonetarySignPosition = signpos;
 
2176
}
 
2177
 
 
2178
void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
 
2179
{
 
2180
  doFormatInit();
 
2181
  m_positivePrefixCurrencySymbol = prefix;
 
2182
}
 
2183
 
 
2184
void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
 
2185
{
 
2186
  doFormatInit();
 
2187
  m_negativePrefixCurrencySymbol = prefix;
 
2188
}
 
2189
 
 
2190
void KLocale::setFracDigits(int digits)
 
2191
{
 
2192
  doFormatInit();
 
2193
  m_fracDigits = digits;
 
2194
}
 
2195
 
 
2196
void KLocale::setMonetaryThousandsSeparator(const QString & separator)
 
2197
{
 
2198
  doFormatInit();
 
2199
  // allow spaces here
 
2200
  m_monetaryThousandsSeparator = separator;
 
2201
}
 
2202
 
 
2203
void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
 
2204
{
 
2205
  doFormatInit();
 
2206
  m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
 
2207
}
 
2208
 
 
2209
void KLocale::setCurrencySymbol(const QString & symbol)
 
2210
{
 
2211
  doFormatInit();
 
2212
  m_currencySymbol = symbol.stripWhiteSpace();
 
2213
}
 
2214
 
 
2215
int KLocale::pageSize() const
 
2216
{
 
2217
  doFormatInit();
 
2218
  return d->pageSize;
 
2219
}
 
2220
 
 
2221
void KLocale::setPageSize(int pageSize)
 
2222
{
 
2223
  // #### check if it's in range??
 
2224
  doFormatInit();
 
2225
  d->pageSize = pageSize;
 
2226
}
 
2227
 
 
2228
KLocale::MeasureSystem KLocale::measureSystem() const
 
2229
{
 
2230
  doFormatInit();
 
2231
  return d->measureSystem;
 
2232
}
 
2233
 
 
2234
void KLocale::setMeasureSystem(MeasureSystem value)
 
2235
{
 
2236
  doFormatInit();
 
2237
  d->measureSystem = value;
 
2238
}
 
2239
 
 
2240
QString KLocale::defaultLanguage()
 
2241
{
 
2242
  return QString::fromLatin1("en_US");
 
2243
}
 
2244
 
 
2245
QString KLocale::defaultCountry()
 
2246
{
 
2247
  return QString::fromLatin1("C");
 
2248
}
 
2249
 
 
2250
const char * KLocale::encoding() const
 
2251
{
 
2252
#ifdef Q_WS_WIN
 
2253
  if (0==qstrcmp("System", codecForEncoding()->name()))
 
2254
  {
 
2255
    //win32 returns "System" codec name here but KDE apps expect a real name:
 
2256
    strcpy(d->win32SystemEncoding, "cp ");
 
2257
    if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT), 
 
2258
      LOCALE_IDEFAULTANSICODEPAGE, d->win32SystemEncoding+3, sizeof(d->win32SystemEncoding)-3-1 ))
 
2259
    {
 
2260
      return d->win32SystemEncoding;
 
2261
    }
 
2262
  }
 
2263
#endif
 
2264
  return codecForEncoding()->name();
 
2265
}
 
2266
 
 
2267
int KLocale::encodingMib() const
 
2268
{
 
2269
  return codecForEncoding()->mibEnum();
 
2270
}
 
2271
 
 
2272
int KLocale::fileEncodingMib() const
 
2273
{
 
2274
  if (d->utf8FileEncoding)
 
2275
     return 106;
 
2276
  return codecForEncoding()->mibEnum();
 
2277
}
 
2278
 
 
2279
QTextCodec * KLocale::codecForEncoding() const
 
2280
{
 
2281
  return d->codecForEncoding;
 
2282
}
 
2283
 
 
2284
bool KLocale::setEncoding(int mibEnum)
 
2285
{
 
2286
  QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
 
2287
  if (codec)
 
2288
    d->codecForEncoding = codec;
 
2289
 
 
2290
  return codec != 0;
 
2291
}
 
2292
 
 
2293
QStringList KLocale::languagesTwoAlpha() const
 
2294
{
 
2295
  if (d->langTwoAlpha.count())
 
2296
     return d->langTwoAlpha;
 
2297
 
 
2298
  const QStringList &origList = languageList();
 
2299
 
 
2300
  QStringList result;
 
2301
 
 
2302
  KConfig config(QString::fromLatin1("language.codes"), true, false);
 
2303
  config.setGroup("TwoLetterCodes");
 
2304
 
 
2305
  for ( QStringList::ConstIterator it = origList.begin();
 
2306
        it != origList.end();
 
2307
        ++it )
 
2308
    {
 
2309
      QString lang = *it;
 
2310
      QStringList langLst;
 
2311
      if (config.hasKey( lang ))
 
2312
         langLst = config.readListEntry( lang );
 
2313
      else
 
2314
      {
 
2315
         int i = lang.find('_');
 
2316
         if (i >= 0)
 
2317
            lang.truncate(i);
 
2318
         langLst << lang;
 
2319
      }
 
2320
 
 
2321
      for ( QStringList::ConstIterator langIt = langLst.begin();
 
2322
            langIt != langLst.end();
 
2323
            ++langIt )
 
2324
        {
 
2325
          if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
 
2326
            result += *langIt;
 
2327
        }
 
2328
    }
 
2329
  d->langTwoAlpha = result;
 
2330
  return result;
 
2331
}
 
2332
 
 
2333
QStringList KLocale::allLanguagesTwoAlpha() const
 
2334
{
 
2335
  if (!d->languages)
 
2336
    d->languages = new KConfig("all_languages", true, false, "locale");
 
2337
 
 
2338
  return d->languages->groupList();
 
2339
}
 
2340
 
 
2341
QString KLocale::twoAlphaToLanguageName(const QString &code) const
 
2342
{
 
2343
  if (!d->languages)
 
2344
    d->languages = new KConfig("all_languages", true, false, "locale");
 
2345
 
 
2346
  QString groupName = code;
 
2347
  const int i = groupName.find('_');
 
2348
  groupName.replace(0, i, groupName.left(i).lower());
 
2349
 
 
2350
  d->languages->setGroup(groupName);
 
2351
  return d->languages->readEntry("Name");
 
2352
}
 
2353
 
 
2354
QStringList KLocale::allCountriesTwoAlpha() const
 
2355
{
 
2356
  QStringList countries;
 
2357
  QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
 
2358
  for(QStringList::ConstIterator it = paths.begin();
 
2359
      it != paths.end(); ++it)
 
2360
  {
 
2361
    QString code = (*it).mid((*it).length()-16, 2);
 
2362
    if (code != "/C")
 
2363
       countries.append(code);
 
2364
  }
 
2365
  return countries;
 
2366
}
 
2367
 
 
2368
QString KLocale::twoAlphaToCountryName(const QString &code) const
 
2369
{
 
2370
  KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
 
2371
  cfg.setGroup("KCM Locale");
 
2372
  return cfg.readEntry("Name");
 
2373
}
 
2374
 
 
2375
void KLocale::setCalendar(const QString & calType)
 
2376
{
 
2377
  doFormatInit();
 
2378
 
 
2379
  d->calendarType = calType;
 
2380
 
 
2381
  delete d->calendar;
 
2382
  d->calendar = 0;
 
2383
}
 
2384
 
 
2385
QString KLocale::calendarType() const
 
2386
{
 
2387
  doFormatInit();
 
2388
 
 
2389
  return d->calendarType;
 
2390
}
 
2391
 
 
2392
const KCalendarSystem * KLocale::calendar() const
 
2393
{
 
2394
  doFormatInit();
 
2395
 
 
2396
  // Check if it's the correct calendar?!?
 
2397
  if ( !d->calendar )
 
2398
    d->calendar = KCalendarSystemFactory::create( d->calendarType, this );
 
2399
 
 
2400
  return d->calendar;
 
2401
}
 
2402
 
 
2403
KLocale::KLocale(const KLocale & rhs)
 
2404
{
 
2405
  d = new KLocalePrivate;
 
2406
 
 
2407
  *this = rhs;
 
2408
}
 
2409
 
 
2410
KLocale & KLocale::operator=(const KLocale & rhs)
 
2411
{
 
2412
  // Numbers and money
 
2413
  m_decimalSymbol = rhs.m_decimalSymbol;
 
2414
  m_thousandsSeparator = rhs.m_thousandsSeparator;
 
2415
  m_currencySymbol = rhs.m_currencySymbol;
 
2416
  m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
 
2417
  m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
 
2418
  m_positiveSign = rhs.m_positiveSign;
 
2419
  m_negativeSign = rhs.m_negativeSign;
 
2420
  m_fracDigits = rhs.m_fracDigits;
 
2421
  m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
 
2422
  m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
 
2423
  m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
 
2424
  m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
 
2425
 
 
2426
  // Date and time
 
2427
  m_timeFormat = rhs.m_timeFormat;
 
2428
  m_dateFormat = rhs.m_dateFormat;
 
2429
  m_dateFormatShort = rhs.m_dateFormatShort;
 
2430
 
 
2431
  m_language = rhs.m_language;
 
2432
  m_country = rhs.m_country;
 
2433
 
 
2434
  // the assignment operator works here
 
2435
  *d = *rhs.d;
 
2436
  d->languages = 0; // Don't copy languages
 
2437
  d->calendar = 0; // Don't copy the calendar
 
2438
 
 
2439
  return *this;
 
2440
}
 
2441
 
 
2442
bool KLocale::setCharset(const QString & ) { return true; }
 
2443
QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); }
 
2444
 
 
2445
// KDE4: remove
 
2446
#if 0
 
2447
void nothing() { i18n("&Next"); }
 
2448
#endif