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