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