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