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