00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025
00026 #include <stdlib.h>
00027
00028 #include <qtextcodec.h>
00029 #include <qfile.h>
00030 #include <qprinter.h>
00031 #include <qdatetime.h>
00032 #include <qfileinfo.h>
00033 #include <qregexp.h>
00034
00035 #include "kcatalogue.h"
00036 #include "kglobal.h"
00037 #include "kstandarddirs.h"
00038 #include "ksimpleconfig.h"
00039 #include "kinstance.h"
00040 #include "kconfig.h"
00041 #include "kdebug.h"
00042 #include "kcalendarsystem.h"
00043 #include "kcalendarsystemfactory.h"
00044 #include "klocale.h"
00045
00046 #ifdef Q_WS_WIN
00047 #include <windows.h>
00048 #endif
00049
00050 static const char * const SYSTEM_MESSAGES = "kdelibs";
00051
00052 static const char *maincatalogue = 0;
00053
00054 class KLocalePrivate
00055 {
00056 public:
00057 int weekStartDay;
00058 bool nounDeclension;
00059 bool dateMonthNamePossessive;
00060 QStringList languageList;
00061 QStringList catalogNames;
00062 QValueList<KCatalogue> catalogues;
00063 QString encoding;
00064 QTextCodec * codecForEncoding;
00065 KConfig * config;
00066 bool formatInited;
00067 int pageSize;
00068 KLocale::MeasureSystem measureSystem;
00069 QStringList langTwoAlpha;
00070 KConfig *languages;
00071
00072 QString calendarType;
00073 KCalendarSystem * calendar;
00074 bool utf8FileEncoding;
00075 QString appName;
00076 #ifdef Q_WS_WIN
00077 char win32SystemEncoding[3+7];
00078 #endif
00079 };
00080
00081 static KLocale *this_klocale = 0;
00082
00083 KLocale::KLocale( const QString & catalog, KConfig * config )
00084 {
00085 d = new KLocalePrivate;
00086 d->config = config;
00087 d->languages = 0;
00088 d->calendar = 0;
00089 d->formatInited = false;
00090
00091 initEncoding(0);
00092 initFileNameEncoding(0);
00093
00094 KConfig *cfg = d->config;
00095 this_klocale = this;
00096 if (!cfg) cfg = KGlobal::instance()->config();
00097 this_klocale = 0;
00098 Q_ASSERT( cfg );
00099
00100 d->appName = catalog;
00101 initLanguageList( cfg, config == 0);
00102 initMainCatalogues(catalog);
00103 }
00104
00105 QString KLocale::_initLanguage(KConfigBase *config)
00106 {
00107 if (this_klocale)
00108 {
00109
00110 this_klocale->initLanguageList((KConfig *) config, true);
00111
00112 return this_klocale->language();
00113 }
00114 return QString::null;
00115 }
00116
00117 void KLocale::initMainCatalogues(const QString & catalog)
00118 {
00119
00120 QString mainCatalogue = catalog;
00121 if (maincatalogue)
00122 mainCatalogue = QString::fromLatin1(maincatalogue);
00123
00124 if (mainCatalogue.isEmpty()) {
00125 kdDebug(173) << "KLocale instance created called without valid "
00126 << "catalog! Give an argument or call setMainCatalogue "
00127 << "before init" << endl;
00128 }
00129 else {
00130
00131 d->catalogNames.append( mainCatalogue );
00132 d->catalogNames.append( SYSTEM_MESSAGES );
00133 d->catalogNames.append( "kio" );
00134 KGlobal::dirs()->addResourceDir("locale", "/usr/share/locale");
00135 d->catalogNames.append( "kickoff" );
00136 d->catalogNames.append( "xdg-user-dirs" );
00137 updateCatalogues();
00138 }
00139 }
00140
00141 void KLocale::initLanguageList(KConfig * config, bool useEnv)
00142 {
00143 KConfigGroupSaver saver(config, "Locale");
00144
00145 m_country = config->readEntry( "Country" );
00146 if ( m_country.isEmpty() )
00147 m_country = defaultCountry();
00148
00149
00150 QStringList languageList;
00151 if ( useEnv )
00152 languageList += QStringList::split
00153 (':', QFile::decodeName( ::getenv("KDE_LANG") ));
00154
00155 languageList += config->readListEntry("Language", ':');
00156
00157
00158 if ( useEnv )
00159 {
00160
00161 QStringList langs;
00162
00163 langs << QFile::decodeName( ::getenv("LC_ALL") );
00164 langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
00165 langs << QFile::decodeName( ::getenv("LANG") );
00166
00167 for ( QStringList::Iterator it = langs.begin();
00168 it != langs.end();
00169 ++it )
00170 {
00171 QString ln, ct, chrset;
00172 splitLocale(*it, ln, ct, chrset);
00173
00174 if (!ct.isEmpty()) {
00175 langs.insert(it, ln + '_' + ct);
00176 if (!chrset.isEmpty())
00177 langs.insert(it, ln + '_' + ct + '.' + chrset);
00178 }
00179
00180 langs.insert(it, ln);
00181 }
00182
00183 languageList += langs;
00184 }
00185
00186
00187 setLanguage( languageList );
00188 }
00189
00190 void KLocale::initPluralTypes()
00191 {
00192 for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
00193 it != d->catalogues.end();
00194 ++it )
00195 {
00196 QString language = (*it).language();
00197 int pt = pluralType( language );
00198 (*it).setPluralType( pt );
00199 }
00200 }
00201
00202
00203 int KLocale::pluralType( const QString & language )
00204 {
00205 for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
00206 it != d->catalogues.end();
00207 ++it )
00208 {
00209 if ( ((*it).name() == SYSTEM_MESSAGES ) && ((*it).language() == language )) {
00210 return pluralType( *it );
00211 }
00212 }
00213
00214 return -1;
00215 }
00216
00217 int KLocale::pluralType( const KCatalogue& catalog )
00218 {
00219 const char* pluralFormString =
00220 I18N_NOOP("_: Dear translator, please do not translate this string "
00221 "in any form, but pick the _right_ value out of "
00222 "NoPlural/TwoForms/French... If not sure what to do mail "
00223 "thd@kde.org and coolo@kde.org, they will tell you. "
00224 "Better leave that out if unsure, the programs will "
00225 "crash!!\nDefinition of PluralForm - to be set by the "
00226 "translator of kdelibs.po");
00227 QString pf (catalog.translate( pluralFormString));
00228 if ( pf.isEmpty() ) {
00229 return -1;
00230 }
00231 else if ( pf == "NoPlural" )
00232 return 0;
00233 else if ( pf == "TwoForms" )
00234 return 1;
00235 else if ( pf == "French" )
00236 return 2;
00237 else if ( pf == "OneTwoRest" )
00238 return 3;
00239 else if ( pf == "Russian" )
00240 return 4;
00241 else if ( pf == "Polish" )
00242 return 5;
00243 else if ( pf == "Slovenian" )
00244 return 6;
00245 else if ( pf == "Lithuanian" )
00246 return 7;
00247 else if ( pf == "Czech" )
00248 return 8;
00249 else if ( pf == "Slovak" )
00250 return 9;
00251 else if ( pf == "Maltese" )
00252 return 10;
00253 else if ( pf == "Arabic" )
00254 return 11;
00255 else if ( pf == "Balcan" )
00256 return 12;
00257 else if ( pf == "Macedonian" )
00258 return 13;
00259 else if ( pf == "Gaeilge" )
00260 return 14;
00261 else {
00262 kdWarning(173) << "Definition of PluralForm is none of "
00263 << "NoPlural/"
00264 << "TwoForms/"
00265 << "French/"
00266 << "OneTwoRest/"
00267 << "Russian/"
00268 << "Polish/"
00269 << "Slovenian/"
00270 << "Lithuanian/"
00271 << "Czech/"
00272 << "Slovak/"
00273 << "Arabic/"
00274 << "Balcan/"
00275 << "Macedonian/"
00276 << "Gaeilge/"
00277 << "Maltese: " << pf << endl;
00278 exit(1);
00279 }
00280 }
00281
00282 void KLocale::doFormatInit() const
00283 {
00284 if ( d->formatInited ) return;
00285
00286 KLocale * that = const_cast<KLocale *>(this);
00287 that->initFormat();
00288
00289 d->formatInited = true;
00290 }
00291
00292 void KLocale::initFormat()
00293 {
00294 KConfig *config = d->config;
00295 if (!config) config = KGlobal::instance()->config();
00296 Q_ASSERT( config );
00297
00298 kdDebug(173) << "KLocale::initFormat" << endl;
00299
00300
00301
00302
00303 KLocale *lsave = KGlobal::_locale;
00304 KGlobal::_locale = this;
00305
00306 KConfigGroupSaver saver(config, "Locale");
00307
00308 KSimpleConfig entry(locate("locale",
00309 QString::fromLatin1("l10n/%1/entry.desktop")
00310 .arg(m_country)), true);
00311 entry.setGroup("KCM Locale");
00312
00313
00314 #define readConfigEntry(key, default, save) \
00315 save = entry.readEntry(key, QString::fromLatin1(default)); \
00316 save = config->readEntry(key, save);
00317
00318 #define readConfigNumEntry(key, default, save, type) \
00319 save = (type)entry.readNumEntry(key, default); \
00320 save = (type)config->readNumEntry(key, save);
00321
00322 #define readConfigBoolEntry(key, default, save) \
00323 save = entry.readBoolEntry(key, default); \
00324 save = config->readBoolEntry(key, save);
00325
00326 readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
00327 readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
00328 m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null );
00329
00330
00331 readConfigEntry("PositiveSign", "", m_positiveSign);
00332 readConfigEntry("NegativeSign", "-", m_negativeSign);
00333
00334
00335 readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
00336 readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
00337 readConfigEntry("MonetaryThousandsSeparator", ",",
00338 m_monetaryThousandsSeparator);
00339 m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null);
00340
00341 readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
00342 readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
00343 m_positivePrefixCurrencySymbol);
00344 readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
00345 m_negativePrefixCurrencySymbol);
00346 readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
00347 m_positiveMonetarySignPosition, SignPosition);
00348 readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
00349 m_negativeMonetarySignPosition, SignPosition);
00350
00351
00352
00353 readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
00354 readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
00355 readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
00356 readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
00357
00358
00359 readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
00360 readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
00361 MeasureSystem);
00362 readConfigEntry("CalendarSystem", "gregorian", d->calendarType);
00363 delete d->calendar;
00364 d->calendar = 0;
00365
00366
00367
00368 KSimpleConfig language(locate("locale",
00369 QString::fromLatin1("%1/entry.desktop")
00370 .arg(m_language)), true);
00371 language.setGroup("KCM Locale");
00372 #define read3ConfigBoolEntry(key, default, save) \
00373 save = entry.readBoolEntry(key, default); \
00374 save = language.readBoolEntry(key, save); \
00375 save = config->readBoolEntry(key, save);
00376
00377 read3ConfigBoolEntry("NounDeclension", false, d->nounDeclension);
00378 read3ConfigBoolEntry("DateMonthNamePossessive", false,
00379 d->dateMonthNamePossessive);
00380
00381
00382 KGlobal::_locale = lsave;
00383 }
00384
00385 bool KLocale::setCountry(const QString & country)
00386 {
00387
00388 if ( country.isEmpty() )
00389 return false;
00390
00391 m_country = country;
00392
00393 d->formatInited = false;
00394
00395 return true;
00396 }
00397
00398 QString KLocale::catalogueFileName(const QString & language,
00399 const KCatalogue & catalog)
00400 {
00401 QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
00402 .arg( language )
00403 .arg( catalog.name() );
00404
00405 return locate( "locale", path );
00406 }
00407
00408 bool KLocale::setLanguage(const QString & language)
00409 {
00410 if ( d->languageList.contains( language ) ) {
00411 d->languageList.remove( language );
00412 }
00413 d->languageList.prepend( language );
00414
00415 m_language = language;
00416
00417
00418
00419 updateCatalogues();
00420
00421 d->formatInited = false;
00422
00423 return true;
00424 }
00425
00426 bool KLocale::setLanguage(const QStringList & languages)
00427 {
00428 QStringList languageList( languages );
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 for( QStringList::Iterator it = languageList.fromLast();
00440 it != languageList.begin(); --it )
00441 {
00442
00443 bool bIsTranslated = isApplicationTranslatedInto( *it );
00444 if ( languageList.contains(*it) > 1 || (*it).isEmpty() || (!bIsTranslated) ) {
00445
00446 it = languageList.remove( it );
00447 }
00448 }
00449
00450
00451
00452 if ( languageList.begin() != languageList.end() ) {
00453 QStringList::Iterator it = languageList.begin();
00454
00455 if( (*it).isEmpty() || !(isApplicationTranslatedInto( *it )) ) {
00456
00457 languageList.remove( it );
00458 }
00459 }
00460
00461 if ( languageList.isEmpty() ) {
00462
00463 languageList.append( defaultLanguage() );
00464 }
00465 m_language = languageList.first();
00466
00467 d->languageList = languageList;
00468 d->langTwoAlpha.clear();
00469
00470
00471
00472 updateCatalogues();
00473
00474 return true;
00475 }
00476
00477 bool KLocale::isApplicationTranslatedInto( const QString & language)
00478 {
00479 if ( language.isEmpty() ) {
00480 return false;
00481 }
00482
00483 if ( language == defaultLanguage() ) {
00484
00485 return true;
00486 }
00487
00488 QString appName = d->appName;
00489 if (maincatalogue) {
00490 appName = QString::fromLatin1(maincatalogue);
00491 }
00492
00493
00494
00495
00496
00497
00498 QString sFileName = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
00499 .arg( language )
00500 .arg( appName );
00501
00502
00503 QString sAbsFileName = locate( "locale", sFileName );
00504
00505 return ! sAbsFileName.isEmpty();
00506 }
00507
00508 void KLocale::splitLocale(const QString & aStr,
00509 QString & language,
00510 QString & country,
00511 QString & chrset)
00512 {
00513 QString str = aStr;
00514
00515
00516 int f = str.find(':');
00517 if (f >= 0)
00518 str.truncate(f);
00519
00520 country = QString::null;
00521 chrset = QString::null;
00522 language = QString::null;
00523
00524 f = str.find('.');
00525 if (f >= 0)
00526 {
00527 chrset = str.mid(f + 1);
00528 str.truncate(f);
00529 }
00530
00531 f = str.find('_');
00532 if (f >= 0)
00533 {
00534 country = str.mid(f + 1);
00535 str.truncate(f);
00536 }
00537
00538 language = str;
00539 }
00540
00541 QString KLocale::language() const
00542 {
00543 return m_language;
00544 }
00545
00546 QString KLocale::country() const
00547 {
00548 return m_country;
00549 }
00550
00551 QString KLocale::monthName(int i, bool shortName) const
00552 {
00553 if ( shortName )
00554 switch ( i )
00555 {
00556 case 1: return translate("January", "Jan");
00557 case 2: return translate("February", "Feb");
00558 case 3: return translate("March", "Mar");
00559 case 4: return translate("April", "Apr");
00560 case 5: return translate("May short", "May");
00561 case 6: return translate("June", "Jun");
00562 case 7: return translate("July", "Jul");
00563 case 8: return translate("August", "Aug");
00564 case 9: return translate("September", "Sep");
00565 case 10: return translate("October", "Oct");
00566 case 11: return translate("November", "Nov");
00567 case 12: return translate("December", "Dec");
00568 }
00569 else
00570 switch (i)
00571 {
00572 case 1: return translate("January");
00573 case 2: return translate("February");
00574 case 3: return translate("March");
00575 case 4: return translate("April");
00576 case 5: return translate("May long", "May");
00577 case 6: return translate("June");
00578 case 7: return translate("July");
00579 case 8: return translate("August");
00580 case 9: return translate("September");
00581 case 10: return translate("October");
00582 case 11: return translate("November");
00583 case 12: return translate("December");
00584 }
00585
00586 return QString::null;
00587 }
00588
00589 QString KLocale::monthNamePossessive(int i, bool shortName) const
00590 {
00591 if ( shortName )
00592 switch ( i )
00593 {
00594 case 1: return translate("of January", "of Jan");
00595 case 2: return translate("of February", "of Feb");
00596 case 3: return translate("of March", "of Mar");
00597 case 4: return translate("of April", "of Apr");
00598 case 5: return translate("of May short", "of May");
00599 case 6: return translate("of June", "of Jun");
00600 case 7: return translate("of July", "of Jul");
00601 case 8: return translate("of August", "of Aug");
00602 case 9: return translate("of September", "of Sep");
00603 case 10: return translate("of October", "of Oct");
00604 case 11: return translate("of November", "of Nov");
00605 case 12: return translate("of December", "of Dec");
00606 }
00607 else
00608 switch (i)
00609 {
00610 case 1: return translate("of January");
00611 case 2: return translate("of February");
00612 case 3: return translate("of March");
00613 case 4: return translate("of April");
00614 case 5: return translate("of May long", "of May");
00615 case 6: return translate("of June");
00616 case 7: return translate("of July");
00617 case 8: return translate("of August");
00618 case 9: return translate("of September");
00619 case 10: return translate("of October");
00620 case 11: return translate("of November");
00621 case 12: return translate("of December");
00622 }
00623
00624 return QString::null;
00625 }
00626
00627 QString KLocale::weekDayName (int i, bool shortName) const
00628 {
00629 return calendar()->weekDayName(i, shortName);
00630 }
00631
00632 void KLocale::insertCatalogue( const QString & catalog )
00633 {
00634 if ( !d->catalogNames.contains( catalog) ) {
00635 d->catalogNames.append( catalog );
00636 }
00637 updateCatalogues( );
00638 }
00639
00640 void KLocale::updateCatalogues( )
00641 {
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
00656 it != d->catalogues.end(); )
00657 {
00658 it = d->catalogues.remove(it);
00659 }
00660
00661
00662
00663
00664
00665 for ( QStringList::ConstIterator itLangs = d->languageList.begin();
00666 itLangs != d->languageList.end(); ++itLangs)
00667 {
00668 for ( QStringList::ConstIterator itNames = d->catalogNames.begin();
00669 itNames != d->catalogNames.end(); ++itNames)
00670 {
00671 KCatalogue cat( *itNames, *itLangs );
00672 d->catalogues.append( cat );
00673 }
00674 }
00675 initPluralTypes();
00676 }
00677
00678
00679
00680
00681 void KLocale::removeCatalogue(const QString &catalog)
00682 {
00683 if ( d->catalogNames.contains( catalog )) {
00684 d->catalogNames.remove( catalog );
00685 if (KGlobal::_instance)
00686 updateCatalogues();
00687 }
00688 }
00689
00690 void KLocale::setActiveCatalogue(const QString &catalog)
00691 {
00692 if ( d->catalogNames.contains( catalog ) ) {
00693 d->catalogNames.remove( catalog );
00694 d->catalogNames.prepend( catalog );
00695 updateCatalogues();
00696 }
00697 }
00698
00699 KLocale::~KLocale()
00700 {
00701 delete d->calendar;
00702 delete d->languages;
00703 delete d;
00704 d = 0L;
00705 }
00706
00707 QString KLocale::translate_priv(const char *msgid,
00708 const char *fallback,
00709 const char **translated,
00710 int* pluralType ) const
00711 {
00712 if ( pluralType) {
00713 *pluralType = -1;
00714 }
00715 if (!msgid || !msgid[0])
00716 {
00717 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00718 << "Fix the program" << endl;
00719 return QString::null;
00720 }
00721
00722 if ( useDefaultLanguage() ) {
00723 return QString::fromUtf8( fallback );
00724 }
00725
00726 for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
00727 it != d->catalogues.end();
00728 ++it )
00729 {
00730
00731
00732
00733 if ( (*it).language() == defaultLanguage() ) {
00734 return QString::fromUtf8( fallback );
00735 }
00736
00737 const char * text = (*it).translate( msgid );
00738
00739 if ( text )
00740 {
00741
00742 if (translated) {
00743 *translated = text;
00744 }
00745 if ( pluralType) {
00746 *pluralType = (*it).pluralType();
00747 }
00748 return QString::fromUtf8( text );
00749 }
00750 }
00751
00752
00753 return QString::fromUtf8( fallback );
00754 }
00755
00756 QString KLocale::translate(const char* msgid) const
00757 {
00758 return translate_priv(msgid, msgid);
00759 }
00760
00761 QString KLocale::translate( const char *index, const char *fallback) const
00762 {
00763 if (!index || !index[0] || !fallback || !fallback[0])
00764 {
00765 kdDebug(173) << "KLocale: trying to look up \"\" in catalog. "
00766 << "Fix the program" << endl;
00767 return QString::null;
00768 }
00769
00770 if ( useDefaultLanguage() )
00771 return QString::fromUtf8( fallback );
00772
00773 char *newstring = new char[strlen(index) + strlen(fallback) + 5];
00774 sprintf(newstring, "_: %s\n%s", index, fallback);
00775
00776 QString r = translate_priv(newstring, fallback);
00777 delete [] newstring;
00778
00779 return r;
00780 }
00781
00782 static QString put_n_in(const QString &orig, unsigned long n)
00783 {
00784 QString ret = orig;
00785 int index = ret.find("%n");
00786 if (index == -1)
00787 return ret;
00788 ret.replace(index, 2, QString::number(n));
00789 return ret;
00790 }
00791
00792 #define EXPECT_LENGTH(x) \
00793 if (forms.count() != x) { \
00794 kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
00795 return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
00796
00797 QString KLocale::translate( const char *singular, const char *plural,
00798 unsigned long n ) const
00799 {
00800 if (!singular || !singular[0] || !plural || !plural[0])
00801 {
00802 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00803 << "Fix the program" << endl;
00804 return QString::null;
00805 }
00806
00807 char *newstring = new char[strlen(singular) + strlen(plural) + 6];
00808 sprintf(newstring, "_n: %s\n%s", singular, plural);
00809
00810 int pluralType = -1;
00811 QString r = translate_priv(newstring, 0, 0, &pluralType);
00812 delete [] newstring;
00813
00814 if ( r.isEmpty() || useDefaultLanguage() || pluralType == -1) {
00815 if ( n == 1 ) {
00816 return put_n_in( QString::fromUtf8( singular ), n );
00817 } else {
00818 QString tmp = QString::fromUtf8( plural );
00819 #ifndef NDEBUG
00820 if (tmp.find("%n") == -1) {
00821 kdDebug() << "the message for i18n should contain a '%n'! " << plural << endl;
00822 }
00823 #endif
00824 return put_n_in( tmp, n );
00825 }
00826 }
00827
00828 QStringList forms = QStringList::split( "\n", r, false );
00829 switch ( pluralType ) {
00830 case 0:
00831 EXPECT_LENGTH( 1 );
00832 return put_n_in( forms[0], n);
00833 case 1:
00834 EXPECT_LENGTH( 2 );
00835 if ( n == 1 )
00836 return put_n_in( forms[0], n);
00837 else
00838 return put_n_in( forms[1], n);
00839 case 2:
00840 EXPECT_LENGTH( 2 );
00841 if ( n == 1 || n == 0 )
00842 return put_n_in( forms[0], n);
00843 else
00844 return put_n_in( forms[1], n);
00845 case 3:
00846 EXPECT_LENGTH( 3 );
00847 if ( n == 1 )
00848 return put_n_in( forms[0], n);
00849 else if ( n == 2 )
00850 return put_n_in( forms[1], n);
00851 else
00852 return put_n_in( forms[2], n);
00853 case 4:
00854 EXPECT_LENGTH( 3 );
00855 if ( n%10 == 1 && n%100 != 11)
00856 return put_n_in( forms[0], n);
00857 else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
00858 return put_n_in( forms[1], n);
00859 else
00860 return put_n_in( forms[2], n);
00861 case 5:
00862 EXPECT_LENGTH( 3 );
00863 if ( n == 1 )
00864 return put_n_in( forms[0], n);
00865 else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
00866 return put_n_in( forms[1], n);
00867 else
00868 return put_n_in( forms[2], n);
00869 case 6:
00870 EXPECT_LENGTH( 4 );
00871 if ( n%100 == 1 )
00872 return put_n_in( forms[1], n);
00873 else if ( n%100 == 2 )
00874 return put_n_in( forms[2], n);
00875 else if ( n%100 == 3 || n%100 == 4 )
00876 return put_n_in( forms[3], n);
00877 else
00878 return put_n_in( forms[0], n);
00879 case 7:
00880 EXPECT_LENGTH( 3 );
00881 if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
00882 return put_n_in( forms[2], n);
00883 else if ( n%10 == 1 )
00884 return put_n_in( forms[0], n);
00885 else
00886 return put_n_in( forms[1], n);
00887 case 8:
00888 case 9:
00889 EXPECT_LENGTH( 3 );
00890 if ( n == 1 )
00891 return put_n_in( forms[0], n);
00892 else if (( n >= 2 ) && ( n <= 4 ))
00893 return put_n_in( forms[1], n);
00894 else
00895 return put_n_in( forms[2], n);
00896 case 10:
00897 EXPECT_LENGTH( 4 );
00898 if ( n == 1 )
00899 return put_n_in( forms[0], n );
00900 else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
00901 return put_n_in( forms[1], n );
00902 else if ( n%100 > 10 && n%100 < 20 )
00903 return put_n_in( forms[2], n );
00904 else
00905 return put_n_in( forms[3], n );
00906 case 11:
00907 EXPECT_LENGTH( 4 );
00908 if (n == 1)
00909 return put_n_in(forms[0], n);
00910 else if (n == 2)
00911 return put_n_in(forms[1], n);
00912 else if ( n < 11)
00913 return put_n_in(forms[2], n);
00914 else
00915 return put_n_in(forms[3], n);
00916 case 12:
00917 EXPECT_LENGTH( 3 );
00918 if (n != 11 && n % 10 == 1)
00919 return put_n_in(forms[0], n);
00920 else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
00921 return put_n_in(forms[1], n);
00922 else
00923 return put_n_in(forms[2], n);
00924 case 13:
00925 EXPECT_LENGTH(3);
00926 if (n % 10 == 1)
00927 return put_n_in(forms[0], n);
00928 else if (n % 10 == 2)
00929 return put_n_in(forms[1], n);
00930 else
00931 return put_n_in(forms[2], n);
00932 case 14:
00933 EXPECT_LENGTH(5);
00934 if (n == 1)
00935 return put_n_in(forms[0], n);
00936 else if (n == 2)
00937 return put_n_in(forms[1], n);
00938 else if (n < 7)
00939 return put_n_in(forms[2], n);
00940 else if (n < 11)
00941 return put_n_in(forms[3], n);
00942 else
00943 return put_n_in(forms[4], n);
00944 }
00945 kdFatal() << "The function should have been returned in another way\n";
00946
00947 return QString::null;
00948 }
00949
00950 QString KLocale::translateQt( const char *context, const char *source,
00951 const char *message) const
00952 {
00953 if (!source || !source[0]) {
00954 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00955 << "Fix the program" << endl;
00956 return QString::null;
00957 }
00958
00959 if ( useDefaultLanguage() ) {
00960 return QString::null;
00961 }
00962
00963 char *newstring = 0;
00964 const char *translation = 0;
00965 QString r;
00966
00967 if ( message && message[0]) {
00968 char *newstring = new char[strlen(source) + strlen(message) + 5];
00969 sprintf(newstring, "_: %s\n%s", source, message);
00970 const char *translation = 0;
00971
00972 r = translate_priv(newstring, source, &translation);
00973 delete [] newstring;
00974 if (translation)
00975 return r;
00976 }
00977
00978 if ( context && context[0] && message && message[0]) {
00979 newstring = new char[strlen(context) + strlen(message) + 5];
00980 sprintf(newstring, "_: %s\n%s", context, message);
00981
00982 r = translate_priv(newstring, source, &translation);
00983 delete [] newstring;
00984 if (translation)
00985 return r;
00986 }
00987
00988 r = translate_priv(source, source, &translation);
00989 if (translation)
00990 return r;
00991 return QString::null;
00992 }
00993
00994 bool KLocale::nounDeclension() const
00995 {
00996 doFormatInit();
00997 return d->nounDeclension;
00998 }
00999
01000 bool KLocale::dateMonthNamePossessive() const
01001 {
01002 doFormatInit();
01003 return d->dateMonthNamePossessive;
01004 }
01005
01006 int KLocale::weekStartDay() const
01007 {
01008 doFormatInit();
01009 return d->weekStartDay;
01010 }
01011
01012 bool KLocale::weekStartsMonday() const
01013 {
01014 doFormatInit();
01015 return (d->weekStartDay==1);
01016 }
01017
01018 QString KLocale::decimalSymbol() const
01019 {
01020 doFormatInit();
01021 return m_decimalSymbol;
01022 }
01023
01024 QString KLocale::thousandsSeparator() const
01025 {
01026 doFormatInit();
01027 return m_thousandsSeparator;
01028 }
01029
01030 QString KLocale::currencySymbol() const
01031 {
01032 doFormatInit();
01033 return m_currencySymbol;
01034 }
01035
01036 QString KLocale::monetaryDecimalSymbol() const
01037 {
01038 doFormatInit();
01039 return m_monetaryDecimalSymbol;
01040 }
01041
01042 QString KLocale::monetaryThousandsSeparator() const
01043 {
01044 doFormatInit();
01045 return m_monetaryThousandsSeparator;
01046 }
01047
01048 QString KLocale::positiveSign() const
01049 {
01050 doFormatInit();
01051 return m_positiveSign;
01052 }
01053
01054 QString KLocale::negativeSign() const
01055 {
01056 doFormatInit();
01057 return m_negativeSign;
01058 }
01059
01060 int KLocale::fracDigits() const
01061 {
01062 doFormatInit();
01063 return m_fracDigits;
01064 }
01065
01066 bool KLocale::positivePrefixCurrencySymbol() const
01067 {
01068 doFormatInit();
01069 return m_positivePrefixCurrencySymbol;
01070 }
01071
01072 bool KLocale::negativePrefixCurrencySymbol() const
01073 {
01074 doFormatInit();
01075 return m_negativePrefixCurrencySymbol;
01076 }
01077
01078 KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
01079 {
01080 doFormatInit();
01081 return m_positiveMonetarySignPosition;
01082 }
01083
01084 KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
01085 {
01086 doFormatInit();
01087 return m_negativeMonetarySignPosition;
01088 }
01089
01090 static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
01091 {
01092 for ( uint l = 0; l < s.length(); l++ )
01093 buffer[index++] = s.at( l );
01094 }
01095
01096 static inline void put_it_in( QChar *buffer, uint& index, int number )
01097 {
01098 buffer[index++] = number / 10 + '0';
01099 buffer[index++] = number % 10 + '0';
01100 }
01101
01102
01103 static void _insertSeparator(QString &str, const QString &separator,
01104 const QString &decimalSymbol)
01105 {
01106
01107 QString mainPart = str.section(decimalSymbol, 0, 0);
01108 QString fracPart = str.section(decimalSymbol, 1, 1,
01109 QString::SectionIncludeLeadingSep);
01110
01111 for (int pos = mainPart.length() - 3; pos > 0; pos -= 3)
01112 mainPart.insert(pos, separator);
01113
01114 str = mainPart + fracPart;
01115 }
01116
01117 QString KLocale::formatMoney(double num,
01118 const QString & symbol,
01119 int precision) const
01120 {
01121
01122 QString currency = symbol.isNull()
01123 ? currencySymbol()
01124 : symbol;
01125 if (precision < 0) precision = fracDigits();
01126
01127
01128 bool neg = num < 0;
01129 QString res = QString::number(neg?-num:num, 'f', precision);
01130
01131
01132 res.replace(QChar('.'), monetaryDecimalSymbol());
01133
01134
01135 _insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
01136
01137
01138 int signpos = neg
01139 ? negativeMonetarySignPosition()
01140 : positiveMonetarySignPosition();
01141 QString sign = neg
01142 ? negativeSign()
01143 : positiveSign();
01144
01145 switch (signpos)
01146 {
01147 case ParensAround:
01148 res.prepend('(');
01149 res.append (')');
01150 break;
01151 case BeforeQuantityMoney:
01152 res.prepend(sign);
01153 break;
01154 case AfterQuantityMoney:
01155 res.append(sign);
01156 break;
01157 case BeforeMoney:
01158 currency.prepend(sign);
01159 break;
01160 case AfterMoney:
01161 currency.append(sign);
01162 break;
01163 }
01164
01165 if (neg?negativePrefixCurrencySymbol():
01166 positivePrefixCurrencySymbol())
01167 {
01168 res.prepend(' ');
01169 res.prepend(currency);
01170 } else {
01171 res.append (' ');
01172 res.append (currency);
01173 }
01174
01175 return res;
01176 }
01177
01178 QString KLocale::formatMoney(const QString &numStr) const
01179 {
01180 return formatMoney(numStr.toDouble());
01181 }
01182
01183 QString KLocale::formatNumber(double num, int precision) const
01184 {
01185 if (precision == -1) precision = 2;
01186
01187 return formatNumber(QString::number(num, 'f', precision), false, 0);
01188 }
01189
01190 QString KLocale::formatLong(long num) const
01191 {
01192 return formatNumber((double)num, 0);
01193 }
01194
01195 QString KLocale::formatNumber(const QString &numStr) const
01196 {
01197 return formatNumber(numStr, true, 2);
01198 }
01199
01200
01201 static void _inc_by_one(QString &str, int position)
01202 {
01203 for (int i = position; i >= 0; i--)
01204 {
01205 char last_char = str[i].latin1();
01206 switch(last_char)
01207 {
01208 case '0':
01209 str[i] = '1';
01210 break;
01211 case '1':
01212 str[i] = '2';
01213 break;
01214 case '2':
01215 str[i] = '3';
01216 break;
01217 case '3':
01218 str[i] = '4';
01219 break;
01220 case '4':
01221 str[i] = '5';
01222 break;
01223 case '5':
01224 str[i] = '6';
01225 break;
01226 case '6':
01227 str[i] = '7';
01228 break;
01229 case '7':
01230 str[i] = '8';
01231 break;
01232 case '8':
01233 str[i] = '9';
01234 break;
01235 case '9':
01236 str[i] = '0';
01237 if (i == 0) str.prepend('1');
01238 continue;
01239 case '.':
01240 continue;
01241 }
01242 break;
01243 }
01244 }
01245
01246
01247 static void _round(QString &str, int precision)
01248 {
01249 int decimalSymbolPos = str.find('.');
01250
01251 if (decimalSymbolPos == -1)
01252 if (precision == 0) return;
01253 else if (precision > 0)
01254 {
01255 str.append('.');
01256 decimalSymbolPos = str.length() - 1;
01257 }
01258
01259
01260 str.append(QString().fill('0', precision));
01261
01262
01263 char last_char = str[decimalSymbolPos + precision + 1].latin1();
01264 switch (last_char)
01265 {
01266 case '0':
01267 case '1':
01268 case '2':
01269 case '3':
01270 case '4':
01271
01272 break;
01273 case '5':
01274 case '6':
01275 case '7':
01276 case '8':
01277 case '9':
01278 _inc_by_one(str, decimalSymbolPos + precision);
01279 break;
01280 default:
01281 break;
01282 }
01283
01284 decimalSymbolPos = str.find('.');
01285 str.truncate(decimalSymbolPos + precision + 1);
01286
01287
01288 if (precision == 0) str = str.section('.', 0, 0);
01289 }
01290
01291 QString KLocale::formatNumber(const QString &numStr, bool round,
01292 int precision) const
01293 {
01294 QString tmpString = numStr;
01295 if ((round && precision < 0) ||
01296 ! QRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
01297 return numStr;
01298
01299
01300
01301 bool neg = (tmpString[0] == '-');
01302 if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
01303
01304
01305 QString mantString = tmpString.section('e', 0, 0,
01306 QString::SectionCaseInsensitiveSeps);
01307 QString expString = tmpString.section('e', 1, 1,
01308 QString::SectionCaseInsensitiveSeps |
01309 QString::SectionIncludeLeadingSep);
01310
01311 if (round) _round(mantString, precision);
01312
01313
01314 mantString.replace(QChar('.'), decimalSymbol());
01315
01316
01317 _insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
01318
01319
01320 mantString.prepend(neg?negativeSign():positiveSign());
01321
01322 return mantString + expString;
01323 }
01324
01325 QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
01326 {
01327 const QString rst = shortFormat?dateFormatShort():dateFormat();
01328
01329 QString buffer;
01330
01331 if ( ! pDate.isValid() ) return buffer;
01332
01333 bool escape = false;
01334
01335 int year = calendar()->year(pDate);
01336 int month = calendar()->month(pDate);
01337
01338 for ( uint format_index = 0; format_index < rst.length(); ++format_index )
01339 {
01340 if ( !escape )
01341 {
01342 if ( rst.at( format_index ).unicode() == '%' )
01343 escape = true;
01344 else
01345 buffer.append(rst.at(format_index));
01346 }
01347 else
01348 {
01349 switch ( rst.at( format_index ).unicode() )
01350 {
01351 case '%':
01352 buffer.append('%');
01353 break;
01354 case 'Y':
01355 buffer.append(calendar()->yearString(pDate, false));
01356 break;
01357 case 'y':
01358 buffer.append(calendar()->yearString(pDate, true));
01359 break;
01360 case 'n':
01361 buffer.append(calendar()->monthString(pDate, true));
01362 break;
01363 case 'e':
01364 buffer.append(calendar()->dayString(pDate, true));
01365 break;
01366 case 'm':
01367 buffer.append(calendar()->monthString(pDate, false));
01368 break;
01369 case 'b':
01370 if (d->nounDeclension && d->dateMonthNamePossessive)
01371 buffer.append(calendar()->monthNamePossessive(month, year, true));
01372 else
01373 buffer.append(calendar()->monthName(month, year, true));
01374 break;
01375 case 'B':
01376 if (d->nounDeclension && d->dateMonthNamePossessive)
01377 buffer.append(calendar()->monthNamePossessive(month, year, false));
01378 else
01379 buffer.append(calendar()->monthName(month, year, false));
01380 break;
01381 case 'd':
01382 buffer.append(calendar()->dayString(pDate, false));
01383 break;
01384 case 'a':
01385 buffer.append(calendar()->weekDayName(pDate, true));
01386 break;
01387 case 'A':
01388 buffer.append(calendar()->weekDayName(pDate, false));
01389 break;
01390 default:
01391 buffer.append(rst.at(format_index));
01392 break;
01393 }
01394 escape = false;
01395 }
01396 }
01397 return buffer;
01398 }
01399
01400 void KLocale::setMainCatalogue(const char *catalog)
01401 {
01402 maincatalogue = catalog;
01403 }
01404
01405 double KLocale::readNumber(const QString &_str, bool * ok) const
01406 {
01407 QString str = _str.stripWhiteSpace();
01408 bool neg = str.find(negativeSign()) == 0;
01409 if (neg)
01410 str.remove( 0, negativeSign().length() );
01411
01412
01413
01414
01415 QString exponentialPart;
01416 int EPos;
01417
01418 EPos = str.find('E', 0, false);
01419
01420 if (EPos != -1)
01421 {
01422 exponentialPart = str.mid(EPos);
01423 str = str.left(EPos);
01424 }
01425
01426 int pos = str.find(decimalSymbol());
01427 QString major;
01428 QString minor;
01429 if ( pos == -1 )
01430 major = str;
01431 else
01432 {
01433 major = str.left(pos);
01434 minor = str.mid(pos + decimalSymbol().length());
01435 }
01436
01437
01438 int thlen = thousandsSeparator().length();
01439 int lastpos = 0;
01440 while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
01441 {
01442
01443 int fromEnd = major.length() - pos;
01444 if ( fromEnd % (3+thlen) != 0
01445 || pos - lastpos > 3
01446 || pos == 0
01447 || (lastpos>0 && pos-lastpos!=3))
01448 {
01449 if (ok) *ok = false;
01450 return 0.0;
01451 }
01452
01453 lastpos = pos;
01454 major.remove( pos, thlen );
01455 }
01456 if (lastpos>0 && major.length()-lastpos!=3)
01457 {
01458 if (ok) *ok = false;
01459 return 0.0;
01460 }
01461
01462 QString tot;
01463 if (neg) tot = '-';
01464
01465 tot += major + '.' + minor + exponentialPart;
01466
01467 return tot.toDouble(ok);
01468 }
01469
01470 double KLocale::readMoney(const QString &_str, bool * ok) const
01471 {
01472 QString str = _str.stripWhiteSpace();
01473 bool neg = false;
01474 bool currencyFound = false;
01475 QString symbol = currencySymbol();
01476
01477 int pos = str.find(symbol);
01478 if ( pos == 0 || pos == (int) str.length()-symbol.length() )
01479 {
01480 str.remove(pos,symbol.length());
01481 str = str.stripWhiteSpace();
01482 currencyFound = true;
01483 }
01484 if (str.isEmpty())
01485 {
01486 if (ok) *ok = false;
01487 return 0;
01488 }
01489
01490
01491 if (negativeMonetarySignPosition() == ParensAround)
01492 {
01493 if (str[0] == '(' && str[str.length()-1] == ')')
01494 {
01495 neg = true;
01496 str.remove(str.length()-1,1);
01497 str.remove(0,1);
01498 }
01499 }
01500 else
01501 {
01502 int i1 = str.find(negativeSign());
01503 if ( i1 == 0 || i1 == (int) str.length()-1 )
01504 {
01505 neg = true;
01506 str.remove(i1,negativeSign().length());
01507 }
01508 }
01509 if (neg) str = str.stripWhiteSpace();
01510
01511
01512
01513 if ( !currencyFound )
01514 {
01515 pos = str.find(symbol);
01516 if ( pos == 0 || pos == (int) str.length()-symbol.length() )
01517 {
01518 str.remove(pos,symbol.length());
01519 str = str.stripWhiteSpace();
01520 }
01521 }
01522
01523
01524 pos = str.find(monetaryDecimalSymbol());
01525 QString major;
01526 QString minior;
01527 if (pos == -1)
01528 major = str;
01529 else
01530 {
01531 major = str.left(pos);
01532 minior = str.mid(pos + monetaryDecimalSymbol().length());
01533 }
01534
01535
01536 int thlen = monetaryThousandsSeparator().length();
01537 int lastpos = 0;
01538 while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
01539 {
01540
01541 int fromEnd = major.length() - pos;
01542 if ( fromEnd % (3+thlen) != 0
01543 || pos - lastpos > 3
01544 || pos == 0
01545 || (lastpos>0 && pos-lastpos!=3))
01546 {
01547 if (ok) *ok = false;
01548 return 0.0;
01549 }
01550 lastpos = pos;
01551 major.remove( pos, thlen );
01552 }
01553 if (lastpos>0 && major.length()-lastpos!=3)
01554 {
01555 if (ok) *ok = false;
01556 return 0.0;
01557 }
01558
01559 QString tot;
01560 if (neg) tot = '-';
01561 tot += major + '.' + minior;
01562 return tot.toDouble(ok);
01563 }
01564
01571 static int readInt(const QString &str, uint &pos)
01572 {
01573 if (!str.at(pos).isDigit()) return -1;
01574 int result = 0;
01575 for (; str.length() > pos && str.at(pos).isDigit(); pos++)
01576 {
01577 result *= 10;
01578 result += str.at(pos).digitValue();
01579 }
01580
01581 return result;
01582 }
01583
01584 QDate KLocale::readDate(const QString &intstr, bool* ok) const
01585 {
01586 QDate date;
01587 date = readDate(intstr, ShortFormat, ok);
01588 if (date.isValid()) return date;
01589 return readDate(intstr, NormalFormat, ok);
01590 }
01591
01592 QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
01593 {
01594 QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
01595 return readDate( intstr, fmt, ok );
01596 }
01597
01598 QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
01599 {
01600
01601 QString str = intstr.simplifyWhiteSpace().lower();
01602 int day = -1, month = -1;
01603
01604 int year = calendar()->year(QDate::currentDate());
01605 uint strpos = 0;
01606 uint fmtpos = 0;
01607
01608 int iLength;
01609
01610 bool error = false;
01611
01612 while (fmt.length() > fmtpos && str.length() > strpos && !error)
01613 {
01614
01615 QChar c = fmt.at(fmtpos++);
01616
01617 if (c != '%') {
01618 if (c.isSpace() && str.at(strpos).isSpace())
01619 strpos++;
01620 else if (c != str.at(strpos++))
01621 error = true;
01622 }
01623 else
01624 {
01625 int j;
01626
01627 if (str.length() > strpos && str.at(strpos).isSpace())
01628 strpos++;
01629
01630 c = fmt.at(fmtpos++);
01631 switch (c)
01632 {
01633 case 'a':
01634 case 'A':
01635
01636 error = true;
01637 j = 1;
01638 while (error && (j < 8)) {
01639 QString s = calendar()->weekDayName(j, c == 'a').lower();
01640 int len = s.length();
01641 if (str.mid(strpos, len) == s)
01642 {
01643 strpos += len;
01644 error = false;
01645 }
01646 j++;
01647 }
01648 break;
01649 case 'b':
01650 case 'B':
01651
01652 error = true;
01653 if (d->nounDeclension && d->dateMonthNamePossessive) {
01654 j = 1;
01655 while (error && (j < 13)) {
01656 QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower();
01657 int len = s.length();
01658 if (str.mid(strpos, len) == s) {
01659 month = j;
01660 strpos += len;
01661 error = false;
01662 }
01663 j++;
01664 }
01665 }
01666 j = 1;
01667 while (error && (j < 13)) {
01668 QString s = calendar()->monthName(j, year, c == 'b').lower();
01669 int len = s.length();
01670 if (str.mid(strpos, len) == s) {
01671 month = j;
01672 strpos += len;
01673 error = false;
01674 }
01675 j++;
01676 }
01677 break;
01678 case 'd':
01679 case 'e':
01680 day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
01681 strpos += iLength;
01682
01683 error = iLength <= 0;
01684 break;
01685
01686 case 'n':
01687 case 'm':
01688 month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
01689 strpos += iLength;
01690
01691 error = iLength <= 0;
01692 break;
01693
01694 case 'Y':
01695 case 'y':
01696 year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
01697 strpos += iLength;
01698
01699 error = iLength <= 0;
01700 break;
01701 }
01702 }
01703 }
01704
01705
01706
01707 if ( fmt.length() > fmtpos || str.length() > strpos )
01708 {
01709 error = true;
01710 }
01711
01712
01713 if ( year != -1 && month != -1 && day != -1 && !error)
01714 {
01715 if (ok) *ok = true;
01716
01717 QDate result;
01718 calendar()->setYMD(result, year, month, day);
01719
01720 return result;
01721 }
01722 else
01723 {
01724 if (ok) *ok = false;
01725 return QDate();
01726 }
01727 }
01728
01729 QTime KLocale::readTime(const QString &intstr, bool *ok) const
01730 {
01731 QTime _time;
01732 _time = readTime(intstr, WithSeconds, ok);
01733 if (_time.isValid()) return _time;
01734 return readTime(intstr, WithoutSeconds, ok);
01735 }
01736
01737 QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
01738 {
01739 QString str = intstr.simplifyWhiteSpace().lower();
01740 QString Format = timeFormat().simplifyWhiteSpace();
01741 if (flags & WithoutSeconds)
01742 Format.remove(QRegExp(".%S"));
01743
01744 int hour = -1, minute = -1;
01745 int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0;
01746 bool g_12h = false;
01747 bool pm = false;
01748 uint strpos = 0;
01749 uint Formatpos = 0;
01750
01751 while (Format.length() > Formatpos || str.length() > strpos)
01752 {
01753 if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
01754
01755 QChar c = Format.at(Formatpos++);
01756
01757 if (c != '%')
01758 {
01759 if (c.isSpace())
01760 strpos++;
01761 else if (c != str.at(strpos++))
01762 goto error;
01763 continue;
01764 }
01765
01766
01767 if (str.length() > strpos && str.at(strpos).isSpace())
01768 strpos++;
01769
01770 c = Format.at(Formatpos++);
01771 switch (c)
01772 {
01773 case 'p':
01774 {
01775 QString s;
01776 s = translate("pm").lower();
01777 int len = s.length();
01778 if (str.mid(strpos, len) == s)
01779 {
01780 pm = true;
01781 strpos += len;
01782 }
01783 else
01784 {
01785 s = translate("am").lower();
01786 len = s.length();
01787 if (str.mid(strpos, len) == s) {
01788 pm = false;
01789 strpos += len;
01790 }
01791 else
01792 goto error;
01793 }
01794 }
01795 break;
01796
01797 case 'k':
01798 case 'H':
01799 g_12h = false;
01800 hour = readInt(str, strpos);
01801 if (hour < 0 || hour > 23)
01802 goto error;
01803
01804 break;
01805
01806 case 'l':
01807 case 'I':
01808 g_12h = true;
01809 hour = readInt(str, strpos);
01810 if (hour < 1 || hour > 12)
01811 goto error;
01812
01813 break;
01814
01815 case 'M':
01816 minute = readInt(str, strpos);
01817 if (minute < 0 || minute > 59)
01818 goto error;
01819
01820 break;
01821
01822 case 'S':
01823 second = readInt(str, strpos);
01824 if (second < 0 || second > 59)
01825 goto error;
01826
01827 break;
01828 }
01829 }
01830 if (g_12h) {
01831 hour %= 12;
01832 if (pm) hour += 12;
01833 }
01834
01835 if (ok) *ok = true;
01836 return QTime(hour, minute, second);
01837
01838 error:
01839 if (ok) *ok = false;
01840
01841 return QTime(-1, -1, -1);
01842 }
01843
01844
01845 QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
01846 {
01847 return formatTime( pTime, includeSecs, false );
01848 }
01849
01850 QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
01851 {
01852 const QString rst = timeFormat();
01853
01854
01855
01856 QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
01857
01858 uint index = 0;
01859 bool escape = false;
01860 int number = 0;
01861
01862 for ( uint format_index = 0; format_index < rst.length(); format_index++ )
01863 {
01864 if ( !escape )
01865 {
01866 if ( rst.at( format_index ).unicode() == '%' )
01867 escape = true;
01868 else
01869 buffer[index++] = rst.at( format_index );
01870 }
01871 else
01872 {
01873 switch ( rst.at( format_index ).unicode() )
01874 {
01875 case '%':
01876 buffer[index++] = '%';
01877 break;
01878 case 'H':
01879 put_it_in( buffer, index, pTime.hour() );
01880 break;
01881 case 'I':
01882 if ( isDuration )
01883 put_it_in( buffer, index, pTime.hour() );
01884 else
01885 put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
01886 break;
01887 case 'M':
01888 put_it_in( buffer, index, pTime.minute() );
01889 break;
01890 case 'S':
01891 if (includeSecs)
01892 put_it_in( buffer, index, pTime.second() );
01893 else if ( index > 0 )
01894 {
01895
01896
01897 --index;
01898 break;
01899 }
01900 break;
01901 case 'k':
01902 number = pTime.hour();
01903 case 'l':
01904
01905 if ( rst.at( format_index ).unicode() == 'l' )
01906 number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
01907 if ( number / 10 )
01908 buffer[index++] = number / 10 + '0';
01909 buffer[index++] = number % 10 + '0';
01910 break;
01911 case 'p':
01912 if ( !isDuration )
01913 {
01914 QString s;
01915 if ( pTime.hour() >= 12 )
01916 put_it_in( buffer, index, translate("pm") );
01917 else
01918 put_it_in( buffer, index, translate("am") );
01919 }
01920 break;
01921 default:
01922 buffer[index++] = rst.at( format_index );
01923 break;
01924 }
01925 escape = false;
01926 }
01927 }
01928 QString ret( buffer, index );
01929 delete [] buffer;
01930 if ( isDuration )
01931 return ret.stripWhiteSpace();
01932 else
01933 return ret;
01934 }
01935
01936 bool KLocale::use12Clock() const
01937 {
01938 if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
01939 (timeFormat().contains(QString::fromLatin1("%l")) > 0))
01940 return true;
01941 else
01942 return false;
01943 }
01944
01945 QString KLocale::languages() const
01946 {
01947 return d->languageList.join( QString::fromLatin1(":") );
01948 }
01949
01950 QStringList KLocale::languageList() const
01951 {
01952 return d->languageList;
01953 }
01954
01955 QString KLocale::formatDateTime(const QDateTime &pDateTime,
01956 bool shortFormat,
01957 bool includeSeconds) const
01958 {
01959 return translate("concatenation of dates and time", "%1 %2")
01960 .arg( formatDate( pDateTime.date(), shortFormat ) )
01961 .arg( formatTime( pDateTime.time(), includeSeconds ) );
01962 }
01963
01964 QString i18n(const char* text)
01965 {
01966 register KLocale *instance = KGlobal::locale();
01967 if (instance)
01968 return instance->translate(text);
01969 return QString::fromUtf8(text);
01970 }
01971
01972 QString i18n(const char* index, const char *text)
01973 {
01974 register KLocale *instance = KGlobal::locale();
01975 if (instance)
01976 return instance->translate(index, text);
01977 return QString::fromUtf8(text);
01978 }
01979
01980 QString i18n(const char* singular, const char* plural, unsigned long n)
01981 {
01982 register KLocale *instance = KGlobal::locale();
01983 if (instance)
01984 return instance->translate(singular, plural, n);
01985 if (n == 1)
01986 return put_n_in(QString::fromUtf8(singular), n);
01987 else
01988 return put_n_in(QString::fromUtf8(plural), n);
01989 }
01990
01991 void KLocale::initInstance()
01992 {
01993 if (KGlobal::_locale)
01994 return;
01995
01996 KInstance *app = KGlobal::instance();
01997 if (app) {
01998 KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
01999
02000
02001 QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
02002 }
02003 else
02004 kdDebug(173) << "no app name available using KLocale - nothing to do\n";
02005 }
02006
02007 QString KLocale::langLookup(const QString &fname, const char *rtype)
02008 {
02009 QStringList search;
02010
02011
02012 const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
02013
02014
02015 for (int id=localDoc.count()-1; id >= 0; --id)
02016 {
02017 QStringList langs = KGlobal::locale()->languageList();
02018 langs.append( "en" );
02019 langs.remove( defaultLanguage() );
02020 QStringList::ConstIterator lang;
02021 for (lang = langs.begin(); lang != langs.end(); ++lang)
02022 search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
02023 }
02024
02025
02026 QStringList::Iterator it;
02027 for (it = search.begin(); it != search.end(); ++it)
02028 {
02029 kdDebug(173) << "Looking for help in: " << *it << endl;
02030
02031 QFileInfo info(*it);
02032 if (info.exists() && info.isFile() && info.isReadable())
02033 return *it;
02034 }
02035
02036 return QString::null;
02037 }
02038
02039 bool KLocale::useDefaultLanguage() const
02040 {
02041 return language() == defaultLanguage();
02042 }
02043
02044 void KLocale::initEncoding(KConfig *)
02045 {
02046 const int mibDefault = 4;
02047
02048
02049 setEncoding( QTextCodec::codecForLocale()->mibEnum() );
02050
02051 if ( !d->codecForEncoding )
02052 {
02053 kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
02054 setEncoding(mibDefault);
02055 }
02056
02057 Q_ASSERT( d->codecForEncoding );
02058 }
02059
02060 void KLocale::initFileNameEncoding(KConfig *)
02061 {
02062
02063
02064 d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0;
02065 if (d->utf8FileEncoding)
02066 {
02067 QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
02068 QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
02069 }
02070
02071
02072 }
02073
02074 QCString KLocale::encodeFileNameUTF8( const QString & fileName )
02075 {
02076 return fileName.utf8();
02077 }
02078
02079 QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
02080 {
02081 return QString::fromUtf8(localFileName);
02082 }
02083
02084 void KLocale::setDateFormat(const QString & format)
02085 {
02086 doFormatInit();
02087 m_dateFormat = format.stripWhiteSpace();
02088 }
02089
02090 void KLocale::setDateFormatShort(const QString & format)
02091 {
02092 doFormatInit();
02093 m_dateFormatShort = format.stripWhiteSpace();
02094 }
02095
02096 void KLocale::setDateMonthNamePossessive(bool possessive)
02097 {
02098 doFormatInit();
02099 d->dateMonthNamePossessive = possessive;
02100 }
02101
02102 void KLocale::setTimeFormat(const QString & format)
02103 {
02104 doFormatInit();
02105 m_timeFormat = format.stripWhiteSpace();
02106 }
02107
02108 void KLocale::setWeekStartsMonday(bool start)
02109 {
02110 doFormatInit();
02111 if (start)
02112 d->weekStartDay = 1;
02113 else
02114 d->weekStartDay = 7;
02115 }
02116
02117 void KLocale::setWeekStartDay(int day)
02118 {
02119 doFormatInit();
02120 if (day>7 || day<1)
02121 d->weekStartDay = 1;
02122 else
02123 d->weekStartDay = day;
02124 }
02125
02126 QString KLocale::dateFormat() const
02127 {
02128 doFormatInit();
02129 return m_dateFormat;
02130 }
02131
02132 QString KLocale::dateFormatShort() const
02133 {
02134 doFormatInit();
02135 return m_dateFormatShort;
02136 }
02137
02138 QString KLocale::timeFormat() const
02139 {
02140 doFormatInit();
02141 return m_timeFormat;
02142 }
02143
02144 void KLocale::setDecimalSymbol(const QString & symbol)
02145 {
02146 doFormatInit();
02147 m_decimalSymbol = symbol.stripWhiteSpace();
02148 }
02149
02150 void KLocale::setThousandsSeparator(const QString & separator)
02151 {
02152 doFormatInit();
02153
02154 m_thousandsSeparator = separator;
02155 }
02156
02157 void KLocale::setPositiveSign(const QString & sign)
02158 {
02159 doFormatInit();
02160 m_positiveSign = sign.stripWhiteSpace();
02161 }
02162
02163 void KLocale::setNegativeSign(const QString & sign)
02164 {
02165 doFormatInit();
02166 m_negativeSign = sign.stripWhiteSpace();
02167 }
02168
02169 void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
02170 {
02171 doFormatInit();
02172 m_positiveMonetarySignPosition = signpos;
02173 }
02174
02175 void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
02176 {
02177 doFormatInit();
02178 m_negativeMonetarySignPosition = signpos;
02179 }
02180
02181 void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
02182 {
02183 doFormatInit();
02184 m_positivePrefixCurrencySymbol = prefix;
02185 }
02186
02187 void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
02188 {
02189 doFormatInit();
02190 m_negativePrefixCurrencySymbol = prefix;
02191 }
02192
02193 void KLocale::setFracDigits(int digits)
02194 {
02195 doFormatInit();
02196 m_fracDigits = digits;
02197 }
02198
02199 void KLocale::setMonetaryThousandsSeparator(const QString & separator)
02200 {
02201 doFormatInit();
02202
02203 m_monetaryThousandsSeparator = separator;
02204 }
02205
02206 void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
02207 {
02208 doFormatInit();
02209 m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
02210 }
02211
02212 void KLocale::setCurrencySymbol(const QString & symbol)
02213 {
02214 doFormatInit();
02215 m_currencySymbol = symbol.stripWhiteSpace();
02216 }
02217
02218 int KLocale::pageSize() const
02219 {
02220 doFormatInit();
02221 return d->pageSize;
02222 }
02223
02224 void KLocale::setPageSize(int pageSize)
02225 {
02226
02227 doFormatInit();
02228 d->pageSize = pageSize;
02229 }
02230
02231 KLocale::MeasureSystem KLocale::measureSystem() const
02232 {
02233 doFormatInit();
02234 return d->measureSystem;
02235 }
02236
02237 void KLocale::setMeasureSystem(MeasureSystem value)
02238 {
02239 doFormatInit();
02240 d->measureSystem = value;
02241 }
02242
02243 QString KLocale::defaultLanguage()
02244 {
02245 return QString::fromLatin1("en_US");
02246 }
02247
02248 QString KLocale::defaultCountry()
02249 {
02250 return QString::fromLatin1("C");
02251 }
02252
02253 const char * KLocale::encoding() const
02254 {
02255 #ifdef Q_WS_WIN
02256 if (0==qstrcmp("System", codecForEncoding()->name()))
02257 {
02258
02259 strcpy(d->win32SystemEncoding, "cp ");
02260 if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT),
02261 LOCALE_IDEFAULTANSICODEPAGE, d->win32SystemEncoding+3, sizeof(d->win32SystemEncoding)-3-1 ))
02262 {
02263 return d->win32SystemEncoding;
02264 }
02265 }
02266 #endif
02267 return codecForEncoding()->name();
02268 }
02269
02270 int KLocale::encodingMib() const
02271 {
02272 return codecForEncoding()->mibEnum();
02273 }
02274
02275 int KLocale::fileEncodingMib() const
02276 {
02277 if (d->utf8FileEncoding)
02278 return 106;
02279 return codecForEncoding()->mibEnum();
02280 }
02281
02282 QTextCodec * KLocale::codecForEncoding() const
02283 {
02284 return d->codecForEncoding;
02285 }
02286
02287 bool KLocale::setEncoding(int mibEnum)
02288 {
02289 QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
02290 if (codec)
02291 d->codecForEncoding = codec;
02292
02293 return codec != 0;
02294 }
02295
02296 QStringList KLocale::languagesTwoAlpha() const
02297 {
02298 if (d->langTwoAlpha.count())
02299 return d->langTwoAlpha;
02300
02301 const QStringList &origList = languageList();
02302
02303 QStringList result;
02304
02305 KConfig config(QString::fromLatin1("language.codes"), true, false);
02306 config.setGroup("TwoLetterCodes");
02307
02308 for ( QStringList::ConstIterator it = origList.begin();
02309 it != origList.end();
02310 ++it )
02311 {
02312 QString lang = *it;
02313 QStringList langLst;
02314 if (config.hasKey( lang ))
02315 langLst = config.readListEntry( lang );
02316 else
02317 {
02318 int i = lang.find('_');
02319 if (i >= 0)
02320 lang.truncate(i);
02321 langLst << lang;
02322 }
02323
02324 for ( QStringList::ConstIterator langIt = langLst.begin();
02325 langIt != langLst.end();
02326 ++langIt )
02327 {
02328 if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
02329 result += *langIt;
02330 }
02331 }
02332 d->langTwoAlpha = result;
02333 return result;
02334 }
02335
02336 QStringList KLocale::allLanguagesTwoAlpha() const
02337 {
02338 if (!d->languages)
02339 d->languages = new KConfig("all_languages", true, false, "locale");
02340
02341 return d->languages->groupList();
02342 }
02343
02344 QString KLocale::twoAlphaToLanguageName(const QString &code) const
02345 {
02346 if (!d->languages)
02347 d->languages = new KConfig("all_languages", true, false, "locale");
02348
02349 QString groupName = code;
02350 const int i = groupName.find('_');
02351 groupName.replace(0, i, groupName.left(i).lower());
02352
02353 d->languages->setGroup(groupName);
02354 return d->languages->readEntry("Name");
02355 }
02356
02357 QStringList KLocale::allCountriesTwoAlpha() const
02358 {
02359 QStringList countries;
02360 QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
02361 for(QStringList::ConstIterator it = paths.begin();
02362 it != paths.end(); ++it)
02363 {
02364 QString code = (*it).mid((*it).length()-16, 2);
02365 if (code != "/C")
02366 countries.append(code);
02367 }
02368 return countries;
02369 }
02370
02371 QString KLocale::twoAlphaToCountryName(const QString &code) const
02372 {
02373 KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
02374 cfg.setGroup("KCM Locale");
02375 return cfg.readEntry("Name");
02376 }
02377
02378 void KLocale::setCalendar(const QString & calType)
02379 {
02380 doFormatInit();
02381
02382 d->calendarType = calType;
02383
02384 delete d->calendar;
02385 d->calendar = 0;
02386 }
02387
02388 QString KLocale::calendarType() const
02389 {
02390 doFormatInit();
02391
02392 return d->calendarType;
02393 }
02394
02395 const KCalendarSystem * KLocale::calendar() const
02396 {
02397 doFormatInit();
02398
02399
02400 if ( !d->calendar )
02401 d->calendar = KCalendarSystemFactory::create( d->calendarType, this );
02402
02403 return d->calendar;
02404 }
02405
02406 KLocale::KLocale(const KLocale & rhs)
02407 {
02408 d = new KLocalePrivate;
02409
02410 *this = rhs;
02411 }
02412
02413 KLocale & KLocale::operator=(const KLocale & rhs)
02414 {
02415
02416 m_decimalSymbol = rhs.m_decimalSymbol;
02417 m_thousandsSeparator = rhs.m_thousandsSeparator;
02418 m_currencySymbol = rhs.m_currencySymbol;
02419 m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
02420 m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
02421 m_positiveSign = rhs.m_positiveSign;
02422 m_negativeSign = rhs.m_negativeSign;
02423 m_fracDigits = rhs.m_fracDigits;
02424 m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
02425 m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
02426 m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
02427 m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
02428
02429
02430 m_timeFormat = rhs.m_timeFormat;
02431 m_dateFormat = rhs.m_dateFormat;
02432 m_dateFormatShort = rhs.m_dateFormatShort;
02433
02434 m_language = rhs.m_language;
02435 m_country = rhs.m_country;
02436
02437
02438 *d = *rhs.d;
02439 d->languages = 0;
02440 d->calendar = 0;
02441
02442 return *this;
02443 }
02444
02445 bool KLocale::setCharset(const QString & ) { return true; }
02446 QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); }
02447
02448
02449 #if 0
02450 void nothing() { i18n("&Next"); }
02451 #endif