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