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