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