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