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 int plural_form;
00055 bool nounDeclension;
00056 bool dateMonthNamePossessive;
00057 QStringList languageList;
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 QString first_language;
00071 bool utf8FileEncoding;
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
00083 initCatalogue(catalog);
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 if (m_language.isEmpty())
00094 initLanguage(cfg, config == 0);
00095 }
00096
00097 QString KLocale::_initLanguage(KConfigBase *config)
00098 {
00099 if (this_klocale)
00100 {
00101
00102 this_klocale->initLanguage((KConfig *) config, true);
00103 return this_klocale->language();
00104 }
00105 return QString::null;
00106 }
00107
00108 void KLocale::initCatalogue(const QString & catalog)
00109 {
00110
00111 QString mainCatalogue = catalog;
00112 if (maincatalogue)
00113 mainCatalogue = QString::fromLatin1(maincatalogue);
00114
00115 if (mainCatalogue.isEmpty()) {
00116 kdDebug(173) << "KLocale instance created called without valid "
00117 << "catalog! Give an argument or call setMainCatalogue "
00118 << "before init" << endl;
00119 }
00120 else
00121 d->catalogues.append( KCatalogue(mainCatalogue ) );
00122
00123
00124 d->catalogues.append( KCatalogue( SYSTEM_MESSAGES ) );
00125 d->catalogues.append( KCatalogue( "kio" ) );
00126 }
00127
00128 void KLocale::initLanguage(KConfig * config, bool useEnv)
00129 {
00130 KConfigGroupSaver saver(config, "Locale");
00131
00132 m_country = config->readEntry( "Country" );
00133 if ( m_country.isEmpty() )
00134 m_country = defaultCountry();
00135
00136
00137 QStringList languageList;
00138 if ( useEnv )
00139 languageList += QStringList::split
00140 (':', QFile::decodeName( ::getenv("KDE_LANG") ));
00141
00142 languageList += config->readListEntry("Language", ':');
00143
00144
00145 if ( useEnv )
00146 {
00147
00148 QStringList langs;
00149
00150 langs << QFile::decodeName( ::getenv("LC_ALL") );
00151 langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
00152 langs << QFile::decodeName( ::getenv("LANG") );
00153 langs << QFile::decodeName( ::getenv("LC_CTYPE") );
00154
00155 for ( QStringList::Iterator it = langs.begin();
00156 it != langs.end();
00157 ++it )
00158 {
00159 QString ln, ct, chrset;
00160 splitLocale(*it, ln, ct, chrset);
00161
00162 if (!ct.isEmpty()) {
00163 langs.insert(it, ln + '_' + ct);
00164 if (!chrset.isEmpty())
00165 langs.insert(it, ln + '_' + ct + '.' + chrset);
00166 }
00167
00168 langs.insert(it, ln);
00169 }
00170
00171 languageList += langs;
00172 }
00173
00174
00175 setLanguage( languageList );
00176 }
00177
00178 void KLocale::doBindInit()
00179 {
00180 for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
00181 it != d->catalogues.end();
00182 ++it )
00183 initCatalogue( *it );
00184
00185 if ( useDefaultLanguage() )
00186 d->plural_form = -1;
00187 else
00188 {
00189 QString pf = translate_priv
00190 ( I18N_NOOP("_: Dear translator, please do not translate this string "
00191 "in any form, but pick the _right_ value out of "
00192 "NoPlural/TwoForms/French... If not sure what to do mail "
00193 "thd@kde.org and coolo@kde.org, they will tell you. "
00194 "Better leave that out if unsure, the programs will "
00195 "crash!!\nDefinition of PluralForm - to be set by the "
00196 "translator of kdelibs.po"), 0);
00197 if ( pf.isEmpty() ) {
00198 kdWarning(173) << "found no definition of PluralForm for " << m_language << endl;
00199 d->plural_form = -1;
00200 } else if ( pf == "NoPlural" )
00201 d->plural_form = 0;
00202 else if ( pf == "TwoForms" )
00203 d->plural_form = 1;
00204 else if ( pf == "French" )
00205 d->plural_form = 2;
00206 else if ( pf == "OneTwoRest" || pf == "Gaeilge" )
00207 d->plural_form = 3;
00208 else if ( pf == "Russian" )
00209 d->plural_form = 4;
00210 else if ( pf == "Polish" )
00211 d->plural_form = 5;
00212 else if ( pf == "Slovenian" )
00213 d->plural_form = 6;
00214 else if ( pf == "Lithuanian" )
00215 d->plural_form = 7;
00216 else if ( pf == "Czech" )
00217 d->plural_form = 8;
00218 else if ( pf == "Slovak" )
00219 d->plural_form = 9;
00220 else if ( pf == "Maltese" )
00221 d->plural_form = 10;
00222 else if ( pf == "Arabic" )
00223 d->plural_form = 11;
00224 else if ( pf == "Balcan" )
00225 d->plural_form = 12;
00226 else if ( pf == "Macedonian" )
00227 d->plural_form = 13;
00228 else {
00229 kdWarning(173) << "Definition of PluralForm is none of "
00230 << "NoPlural/"
00231 << "TwoForms/"
00232 << "French/"
00233 << "OneTwoRest/"
00234 << "Russian/"
00235 << "Polish/"
00236 << "Slovenian/"
00237 << "Lithuanian/"
00238 << "Czech/"
00239 << "Slovak/"
00240 << "Arabic/"
00241 << "Balcan/"
00242 << "Macedonian/"
00243 << "Maltese: " << pf << endl;
00244 exit(1);
00245 }
00246 }
00247
00248 d->formatInited = false;
00249 }
00250
00251 void KLocale::doFormatInit() const
00252 {
00253 if ( d->formatInited ) return;
00254
00255 KLocale * that = const_cast<KLocale *>(this);
00256 that->initFormat();
00257
00258 d->formatInited = true;
00259 }
00260
00261 void KLocale::initFormat()
00262 {
00263 KConfig *config = d->config;
00264 if (!config) config = KGlobal::instance()->config();
00265 Q_ASSERT( config );
00266
00267 kdDebug(173) << "KLocale::initFormat" << endl;
00268
00269
00270
00271
00272 KLocale *lsave = KGlobal::_locale;
00273 KGlobal::_locale = this;
00274
00275 KConfigGroupSaver saver(config, "Locale");
00276
00277 KSimpleConfig entry(locate("locale",
00278 QString::fromLatin1("l10n/%1/entry.desktop")
00279 .arg(m_country)), true);
00280 entry.setGroup("KCM Locale");
00281
00282
00283 #define readConfigEntry(key, default, save) \
00284 save = entry.readEntry(key, QString::fromLatin1(default)); \
00285 save = config->readEntry(key, save);
00286
00287 #define readConfigNumEntry(key, default, save, type) \
00288 save = (type)entry.readNumEntry(key, default); \
00289 save = (type)config->readNumEntry(key, save);
00290
00291 #define readConfigBoolEntry(key, default, save) \
00292 save = entry.readBoolEntry(key, default); \
00293 save = config->readBoolEntry(key, save);
00294
00295 readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
00296 readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
00297 m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null );
00298
00299
00300 readConfigEntry("PositiveSign", "", m_positiveSign);
00301 readConfigEntry("NegativeSign", "-", m_negativeSign);
00302
00303
00304 readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
00305 readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
00306 readConfigEntry("MonetaryThousandsSeparator", ",",
00307 m_monetaryThousandsSeparator);
00308 m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null);
00309
00310 readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
00311 readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
00312 m_positivePrefixCurrencySymbol);
00313 readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
00314 m_negativePrefixCurrencySymbol);
00315 readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
00316 m_positiveMonetarySignPosition, SignPosition);
00317 readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
00318 m_negativeMonetarySignPosition, SignPosition);
00319
00320
00321
00322 readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
00323 readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
00324 readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
00325 readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
00326
00327
00328 readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
00329 readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
00330 MeasureSystem);
00331 readConfigEntry("CalendarSystem", "gregorian", d->calendarType);
00332 delete d->calendar;
00333 d->calendar = 0;
00334
00335
00336
00337 KSimpleConfig language(locate("locale",
00338 QString::fromLatin1("%1/entry.desktop")
00339 .arg(m_language)), true);
00340 language.setGroup("KCM Locale");
00341 #define read3ConfigBoolEntry(key, default, save) \
00342 save = entry.readBoolEntry(key, default); \
00343 save = language.readBoolEntry(key, save); \
00344 save = config->readBoolEntry(key, save);
00345
00346 read3ConfigBoolEntry("NounDeclension", false, d->nounDeclension);
00347 read3ConfigBoolEntry("DateMonthNamePossessive", false,
00348 d->dateMonthNamePossessive);
00349
00350
00351 KGlobal::_locale = lsave;
00352 }
00353
00354 bool KLocale::setCountry(const QString & country)
00355 {
00356
00357 if ( country.isEmpty() )
00358 return false;
00359
00360 m_country = country;
00361
00362 d->formatInited = false;
00363
00364 return true;
00365 }
00366
00367 QString KLocale::catalogueFileName(const QString & language,
00368 const KCatalogue & catalog)
00369 {
00370 QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
00371 .arg( language )
00372 .arg( catalog.name() );
00373
00374 return locate( "locale", path );
00375 }
00376
00377 bool KLocale::isLanguageInstalled(const QString & language) const
00378 {
00379
00380 if ( language.isEmpty() ) return false;
00381
00382 bool bRes = true;
00383 if ( language != defaultLanguage() )
00384 for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
00385 it != d->catalogues.end() && bRes;
00386 ++it )
00387 {
00388 bRes = !catalogueFileName( language, *it ).isNull();
00389 if ( !bRes )
00390 kdDebug(173) << "message catalog not found: "
00391 << (*it).name() << endl;
00392 }
00393
00394 return bRes;
00395 }
00396
00397 bool KLocale::setLanguage(const QString & language)
00398 {
00399 bool bRes = true;
00400
00401 if (d->first_language.isNull() || language != d->first_language)
00402 bRes = isLanguageInstalled( language );
00403
00404 if ( bRes )
00405 {
00406 m_language = language;
00407
00408
00409 if (d->first_language.isNull())
00410 d->first_language = language;
00411
00412 doBindInit();
00413 }
00414
00415 return bRes;
00416 }
00417
00418 bool KLocale::setLanguage(const QStringList & languages)
00419 {
00420 QStringList languageList(languages);
00421
00422
00423
00424 for( QStringList::Iterator it = languageList.fromLast();
00425 it != languageList.begin();
00426 --it )
00427 if ( languageList.contains(*it) > 1 || (*it).isEmpty() )
00428 it = languageList.remove( it );
00429
00430 bool bRes = false;
00431 for ( QStringList::ConstIterator it = languageList.begin();
00432 it != languageList.end();
00433 ++it )
00434 if ( bRes = setLanguage( *it ) )
00435 break;
00436
00437 if ( !bRes )
00438 setLanguage(defaultLanguage());
00439
00440 d->languageList = languageList;
00441 d->langTwoAlpha.clear();
00442
00443 return bRes;
00444 }
00445
00446 void KLocale::splitLocale(const QString & aStr,
00447 QString & language,
00448 QString & country,
00449 QString & chrset)
00450 {
00451 QString str = aStr;
00452
00453
00454 int f = str.find(':');
00455 if (f >= 0)
00456 str.truncate(f);
00457
00458 country = QString::null;
00459 chrset = QString::null;
00460 language = QString::null;
00461
00462 f = str.find('.');
00463 if (f >= 0)
00464 {
00465 chrset = str.mid(f + 1);
00466 str.truncate(f);
00467 }
00468
00469 f = str.find('_');
00470 if (f >= 0)
00471 {
00472 country = str.mid(f + 1);
00473 str.truncate(f);
00474 }
00475
00476 language = str;
00477 }
00478
00479 QString KLocale::language() const
00480 {
00481 return m_language;
00482 }
00483
00484 QString KLocale::country() const
00485 {
00486 return m_country;
00487 }
00488
00489 QString KLocale::monthName(int i, bool shortName) const
00490 {
00491 if ( shortName )
00492 switch ( i )
00493 {
00494 case 1: return translate("January", "Jan");
00495 case 2: return translate("February", "Feb");
00496 case 3: return translate("March", "Mar");
00497 case 4: return translate("April", "Apr");
00498 case 5: return translate("May short", "May");
00499 case 6: return translate("June", "Jun");
00500 case 7: return translate("July", "Jul");
00501 case 8: return translate("August", "Aug");
00502 case 9: return translate("September", "Sep");
00503 case 10: return translate("October", "Oct");
00504 case 11: return translate("November", "Nov");
00505 case 12: return translate("December", "Dec");
00506 }
00507 else
00508 switch (i)
00509 {
00510 case 1: return translate("January");
00511 case 2: return translate("February");
00512 case 3: return translate("March");
00513 case 4: return translate("April");
00514 case 5: return translate("May long", "May");
00515 case 6: return translate("June");
00516 case 7: return translate("July");
00517 case 8: return translate("August");
00518 case 9: return translate("September");
00519 case 10: return translate("October");
00520 case 11: return translate("November");
00521 case 12: return translate("December");
00522 }
00523
00524 return QString::null;
00525 }
00526
00527 QString KLocale::monthNamePossessive(int i, bool shortName) const
00528 {
00529 if ( shortName )
00530 switch ( i )
00531 {
00532 case 1: return translate("of January", "of Jan");
00533 case 2: return translate("of February", "of Feb");
00534 case 3: return translate("of March", "of Mar");
00535 case 4: return translate("of April", "of Apr");
00536 case 5: return translate("of May short", "of May");
00537 case 6: return translate("of June", "of Jun");
00538 case 7: return translate("of July", "of Jul");
00539 case 8: return translate("of August", "of Aug");
00540 case 9: return translate("of September", "of Sep");
00541 case 10: return translate("of October", "of Oct");
00542 case 11: return translate("of November", "of Nov");
00543 case 12: return translate("of December", "of Dec");
00544 }
00545 else
00546 switch (i)
00547 {
00548 case 1: return translate("of January");
00549 case 2: return translate("of February");
00550 case 3: return translate("of March");
00551 case 4: return translate("of April");
00552 case 5: return translate("of May long", "of May");
00553 case 6: return translate("of June");
00554 case 7: return translate("of July");
00555 case 8: return translate("of August");
00556 case 9: return translate("of September");
00557 case 10: return translate("of October");
00558 case 11: return translate("of November");
00559 case 12: return translate("of December");
00560 }
00561
00562 return QString::null;
00563 }
00564
00565 QString KLocale::weekDayName (int i, bool shortName) const
00566 {
00567 if ( shortName )
00568 switch ( i )
00569 {
00570 case 1: return translate("Monday", "Mon");
00571 case 2: return translate("Tuesday", "Tue");
00572 case 3: return translate("Wednesday", "Wed");
00573 case 4: return translate("Thursday", "Thu");
00574 case 5: return translate("Friday", "Fri");
00575 case 6: return translate("Saturday", "Sat");
00576 case 7: return translate("Sunday", "Sun");
00577 }
00578 else
00579 switch ( i )
00580 {
00581 case 1: return translate("Monday");
00582 case 2: return translate("Tuesday");
00583 case 3: return translate("Wednesday");
00584 case 4: return translate("Thursday");
00585 case 5: return translate("Friday");
00586 case 6: return translate("Saturday");
00587 case 7: return translate("Sunday");
00588 }
00589
00590 return QString::null;
00591 }
00592
00593 void KLocale::insertCatalogue( const QString & catalog )
00594 {
00595 KCatalogue cat( catalog );
00596
00597 initCatalogue( cat );
00598
00599 d->catalogues.append( cat );
00600 }
00601
00602 void KLocale::removeCatalogue(const QString &catalog)
00603 {
00604 for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
00605 it != d->catalogues.end(); )
00606 if ((*it).name() == catalog) {
00607 it = d->catalogues.remove(it);
00608 return;
00609 } else
00610 ++it;
00611 }
00612
00613 void KLocale::setActiveCatalogue(const QString &catalog)
00614 {
00615 for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
00616 it != d->catalogues.end(); ++it)
00617 if ((*it).name() == catalog) {
00618 KCatalogue save = *it;
00619 d->catalogues.remove(it);
00620 d->catalogues.prepend(save);
00621 return;
00622 }
00623 }
00624
00625 KLocale::~KLocale()
00626 {
00627 delete d->calendar;
00628 delete d->languages;
00629 delete d;
00630 d = 0L;
00631 }
00632
00633 QString KLocale::translate_priv(const char *msgid,
00634 const char *fallback,
00635 const char **translated) const
00636 {
00637 if (!msgid || !msgid[0])
00638 {
00639 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00640 << "Fix the program" << endl;
00641 return QString::null;
00642 }
00643
00644 if ( useDefaultLanguage() )
00645 return QString::fromUtf8( fallback );
00646
00647 for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
00648 it != d->catalogues.end();
00649 ++it )
00650 {
00651
00652 const char * text = (*it).translate( msgid );
00653
00654 if ( text )
00655 {
00656
00657 if (translated)
00658 *translated = text;
00659 return QString::fromUtf8( text );
00660 }
00661 }
00662
00663
00664 return QString::fromUtf8( fallback );
00665 }
00666
00667 QString KLocale::translate(const char* msgid) const
00668 {
00669 return translate_priv(msgid, msgid);
00670 }
00671
00672 QString KLocale::translate( const char *index, const char *fallback) const
00673 {
00674 if (!index || !index[0] || !fallback || !fallback[0])
00675 {
00676 kdDebug(173) << "KLocale: trying to look up \"\" in catalog. "
00677 << "Fix the program" << endl;
00678 return QString::null;
00679 }
00680
00681 if ( useDefaultLanguage() )
00682 return QString::fromUtf8( fallback );
00683
00684 char *newstring = new char[strlen(index) + strlen(fallback) + 5];
00685 sprintf(newstring, "_: %s\n%s", index, fallback);
00686
00687 QString r = translate_priv(newstring, fallback);
00688 delete [] newstring;
00689
00690 return r;
00691 }
00692
00693 static QString put_n_in(const QString &orig, unsigned long n)
00694 {
00695 QString ret = orig;
00696 int index = ret.find("%n");
00697 if (index == -1)
00698 return ret;
00699 ret.replace(index, 2, QString::number(n));
00700 return ret;
00701 }
00702
00703 #define EXPECT_LENGTH(x) \
00704 if (forms.count() != x) { \
00705 kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
00706 return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
00707
00708 QString KLocale::translate( const char *singular, const char *plural,
00709 unsigned long n ) const
00710 {
00711 if (!singular || !singular[0] || !plural || !plural[0])
00712 {
00713 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00714 << "Fix the program" << endl;
00715 return QString::null;
00716 }
00717
00718 char *newstring = new char[strlen(singular) + strlen(plural) + 6];
00719 sprintf(newstring, "_n: %s\n%s", singular, plural);
00720
00721 QString r = translate_priv(newstring, 0);
00722 delete [] newstring;
00723
00724 if ( r.isEmpty() || useDefaultLanguage() || d->plural_form == -1) {
00725 if ( n == 1 ) {
00726 return put_n_in( QString::fromUtf8( singular ), n );
00727 } else {
00728 QString tmp = QString::fromUtf8( plural );
00729 #ifndef NDEBUG
00730 if (tmp.find("%n") == -1) {
00731 kdWarning() << "the message for i18n should contain a '%n'! " << plural << endl;
00732 }
00733 #endif
00734 return put_n_in( tmp, n );
00735 }
00736 }
00737
00738 QStringList forms = QStringList::split( "\n", r, false );
00739 switch ( d->plural_form ) {
00740 case 0:
00741 EXPECT_LENGTH( 1 );
00742 return put_n_in( forms[0], n);
00743 case 1:
00744 EXPECT_LENGTH( 2 );
00745 if ( n == 1 )
00746 return put_n_in( forms[0], n);
00747 else
00748 return put_n_in( forms[1], n);
00749 case 2:
00750 EXPECT_LENGTH( 2 );
00751 if ( n == 1 || n == 0 )
00752 return put_n_in( forms[0], n);
00753 else
00754 return put_n_in( forms[1], n);
00755 case 3:
00756 EXPECT_LENGTH( 3 );
00757 if ( n == 1 )
00758 return put_n_in( forms[0], n);
00759 else if ( n == 2 )
00760 return put_n_in( forms[1], n);
00761 else
00762 return put_n_in( forms[2], n);
00763 case 4:
00764 EXPECT_LENGTH( 3 );
00765 if ( n%10 == 1 && n%100 != 11)
00766 return put_n_in( forms[0], n);
00767 else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
00768 return put_n_in( forms[1], n);
00769 else
00770 return put_n_in( forms[2], n);
00771 case 5:
00772 EXPECT_LENGTH( 3 );
00773 if ( n == 1 )
00774 return put_n_in( forms[0], n);
00775 else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
00776 return put_n_in( forms[1], n);
00777 else
00778 return put_n_in( forms[2], n);
00779 case 6:
00780 EXPECT_LENGTH( 4 );
00781 if ( n%100 == 1 )
00782 return put_n_in( forms[1], n);
00783 else if ( n%100 == 2 )
00784 return put_n_in( forms[2], n);
00785 else if ( n%100 == 3 || n%100 == 4 )
00786 return put_n_in( forms[3], n);
00787 else
00788 return put_n_in( forms[0], n);
00789 case 7:
00790 EXPECT_LENGTH( 3 );
00791 if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
00792 return put_n_in( forms[2], n);
00793 else if ( n%10 == 1 )
00794 return put_n_in( forms[0], n);
00795 else
00796 return put_n_in( forms[1], n);
00797 case 8:
00798 EXPECT_LENGTH( 3 );
00799 if ( n%100 == 1 )
00800 return put_n_in( forms[0], n);
00801 else if (( n%100 >= 2 ) && ( n%100 <= 4 ))
00802 return put_n_in( forms[1], n);
00803 else
00804 return put_n_in( forms[2], n);
00805 case 9:
00806 EXPECT_LENGTH( 3 );
00807 if ( n == 1 )
00808 return put_n_in( forms[0], n);
00809 else if (( n >= 2 ) && ( n <= 4 ))
00810 return put_n_in( forms[1], n);
00811 else
00812 return put_n_in( forms[2], n);
00813 case 10:
00814 EXPECT_LENGTH( 4 );
00815 if ( n == 1 )
00816 return put_n_in( forms[0], n );
00817 else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
00818 return put_n_in( forms[1], n );
00819 else if ( n%100 > 10 && n%100 < 20 )
00820 return put_n_in( forms[2], n );
00821 else
00822 return put_n_in( forms[3], n );
00823 case 11:
00824 EXPECT_LENGTH( 4 );
00825 if (n == 1)
00826 return put_n_in(forms[0], n);
00827 else if (n == 2)
00828 return put_n_in(forms[1], n);
00829 else if ( n < 11)
00830 return put_n_in(forms[2], n);
00831 else
00832 return put_n_in(forms[3], n);
00833 case 12:
00834 EXPECT_LENGTH( 3 );
00835 if (n != 11 && n % 10 == 1)
00836 return put_n_in(forms[0], n);
00837 else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
00838 return put_n_in(forms[1], n);
00839 else
00840 return put_n_in(forms[2], n);
00841 case 13:
00842 EXPECT_LENGTH(3);
00843 if (n % 10 == 1)
00844 return put_n_in(forms[0], n);
00845 else if (n % 10 == 2)
00846 return put_n_in(forms[1], n);
00847 else
00848 return put_n_in(forms[2], n);
00849 }
00850 kdFatal() << "The function should have been returned in another way\n";
00851
00852 return QString::null;
00853 }
00854
00855 QString KLocale::translateQt( const char *context, const char *source,
00856 const char *message) const
00857 {
00858 if (!source || !source[0]) {
00859 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00860 << "Fix the program" << endl;
00861 return QString::null;
00862 }
00863
00864 if ( useDefaultLanguage() ) {
00865 return QString::null;
00866 }
00867
00868 char *newstring = 0;
00869 const char *translation = 0;
00870 QString r;
00871
00872 if ( message && message[0]) {
00873 char *newstring = new char[strlen(source) + strlen(message) + 5];
00874 sprintf(newstring, "_: %s\n%s", source, message);
00875 const char *translation = 0;
00876
00877 r = translate_priv(newstring, source, &translation);
00878 delete [] newstring;
00879 if (translation)
00880 return r;
00881 }
00882
00883 if ( context && context[0] && message && message[0]) {
00884 newstring = new char[strlen(context) + strlen(message) + 5];
00885 sprintf(newstring, "_: %s\n%s", context, message);
00886
00887 r = translate_priv(newstring, source, &translation);
00888 delete [] newstring;
00889 if (translation)
00890 return r;
00891 }
00892
00893 r = translate_priv(source, source, &translation);
00894 if (translation)
00895 return r;
00896 return QString::null;
00897 }
00898
00899 bool KLocale::nounDeclension() const
00900 {
00901 doFormatInit();
00902 return d->nounDeclension;
00903 }
00904
00905 bool KLocale::dateMonthNamePossessive() const
00906 {
00907 doFormatInit();
00908 return d->dateMonthNamePossessive;
00909 }
00910
00911 int KLocale::weekStartDay() const
00912 {
00913 doFormatInit();
00914 return d->weekStartDay;
00915 }
00916
00917 bool KLocale::weekStartsMonday() const
00918 {
00919 doFormatInit();
00920 return (d->weekStartDay==1);
00921 }
00922
00923 QString KLocale::decimalSymbol() const
00924 {
00925 doFormatInit();
00926 return m_decimalSymbol;
00927 }
00928
00929 QString KLocale::thousandsSeparator() const
00930 {
00931 doFormatInit();
00932 return m_thousandsSeparator;
00933 }
00934
00935 QString KLocale::currencySymbol() const
00936 {
00937 doFormatInit();
00938 return m_currencySymbol;
00939 }
00940
00941 QString KLocale::monetaryDecimalSymbol() const
00942 {
00943 doFormatInit();
00944 return m_monetaryDecimalSymbol;
00945 }
00946
00947 QString KLocale::monetaryThousandsSeparator() const
00948 {
00949 doFormatInit();
00950 return m_monetaryThousandsSeparator;
00951 }
00952
00953 QString KLocale::positiveSign() const
00954 {
00955 doFormatInit();
00956 return m_positiveSign;
00957 }
00958
00959 QString KLocale::negativeSign() const
00960 {
00961 doFormatInit();
00962 return m_negativeSign;
00963 }
00964
00965 int KLocale::fracDigits() const
00966 {
00967 doFormatInit();
00968 return m_fracDigits;
00969 }
00970
00971 bool KLocale::positivePrefixCurrencySymbol() const
00972 {
00973 doFormatInit();
00974 return m_positivePrefixCurrencySymbol;
00975 }
00976
00977 bool KLocale::negativePrefixCurrencySymbol() const
00978 {
00979 doFormatInit();
00980 return m_negativePrefixCurrencySymbol;
00981 }
00982
00983 KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
00984 {
00985 doFormatInit();
00986 return m_positiveMonetarySignPosition;
00987 }
00988
00989 KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
00990 {
00991 doFormatInit();
00992 return m_negativeMonetarySignPosition;
00993 }
00994
00995 static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
00996 {
00997 for ( uint l = 0; l < s.length(); l++ )
00998 buffer[index++] = s.at( l );
00999 }
01000
01001 static inline void put_it_in( QChar *buffer, uint& index, int number )
01002 {
01003 buffer[index++] = number / 10 + '0';
01004 buffer[index++] = number % 10 + '0';
01005 }
01006
01007 QString KLocale::formatMoney(double num,
01008 const QString & symbol,
01009 int precision) const
01010 {
01011
01012 QString currency = symbol.isNull()
01013 ? currencySymbol()
01014 : symbol;
01015 if (precision < 0) precision = fracDigits();
01016
01017
01018 bool neg = num < 0;
01019 QString res = QString::number(neg?-num:num, 'f', precision);
01020 int pos = res.find('.');
01021 if (pos == -1) pos = res.length();
01022 else res.replace(pos, 1, monetaryDecimalSymbol());
01023
01024 while (0 < (pos -= 3))
01025 res.insert(pos, monetaryThousandsSeparator());
01026
01027
01028 int signpos = neg
01029 ? negativeMonetarySignPosition()
01030 : positiveMonetarySignPosition();
01031 QString sign = neg
01032 ? negativeSign()
01033 : positiveSign();
01034
01035 switch (signpos)
01036 {
01037 case ParensAround:
01038 res.prepend('(');
01039 res.append (')');
01040 break;
01041 case BeforeQuantityMoney:
01042 res.prepend(sign);
01043 break;
01044 case AfterQuantityMoney:
01045 res.append(sign);
01046 break;
01047 case BeforeMoney:
01048 currency.prepend(sign);
01049 break;
01050 case AfterMoney:
01051 currency.append(sign);
01052 break;
01053 }
01054
01055 if (neg?negativePrefixCurrencySymbol():
01056 positivePrefixCurrencySymbol())
01057 {
01058 res.prepend(' ');
01059 res.prepend(currency);
01060 } else {
01061 res.append (' ');
01062 res.append (currency);
01063 }
01064
01065 return res;
01066 }
01067
01068 QString KLocale::formatMoney(const QString &numStr) const
01069 {
01070 return formatMoney(numStr.toDouble());
01071 }
01072
01073 QString KLocale::formatNumber(double num, int precision) const
01074 {
01075 bool neg = num < 0;
01076 if (precision == -1) precision = 2;
01077 QString res = QString::number(neg?-num:num, 'f', precision);
01078 int pos = res.find('.');
01079 if (pos == -1) pos = res.length();
01080 else res.replace(pos, 1, decimalSymbol());
01081
01082 while (0 < (pos -= 3))
01083 res.insert(pos, thousandsSeparator());
01084
01085
01086 res.prepend(neg?negativeSign():positiveSign());
01087
01088 return res;
01089 }
01090
01091 QString KLocale::formatLong(long num) const
01092 {
01093 return formatNumber((double)num, 0);
01094 }
01095
01096 QString KLocale::formatNumber(const QString &numStr) const
01097 {
01098 return formatNumber(numStr.toDouble());
01099 }
01100
01101 QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
01102 {
01103 const QString rst = shortFormat?dateFormatShort():dateFormat();
01104
01105 QString buffer;
01106
01107 bool escape = false;
01108
01109 int year = calendar()->year(pDate);
01110 int month = calendar()->month(pDate);
01111
01112 for ( uint format_index = 0; format_index < rst.length(); ++format_index )
01113 {
01114 if ( !escape )
01115 {
01116 if ( rst.at( format_index ).unicode() == '%' )
01117 escape = true;
01118 else
01119 buffer.append(rst.at(format_index));
01120 }
01121 else
01122 {
01123 switch ( rst.at( format_index ).unicode() )
01124 {
01125 case '%':
01126 buffer.append('%');
01127 break;
01128 case 'Y':
01129 buffer.append(calendar()->yearString(pDate, false));
01130 break;
01131 case 'y':
01132 buffer.append(calendar()->yearString(pDate, true));
01133 break;
01134 case 'n':
01135 buffer.append(calendar()->monthString(pDate, true));
01136 break;
01137 case 'e':
01138 buffer.append(calendar()->dayString(pDate, true));
01139 break;
01140 case 'm':
01141 buffer.append(calendar()->monthString(pDate, false));
01142 break;
01143 case 'b':
01144 if (d->nounDeclension && d->dateMonthNamePossessive)
01145 buffer.append(calendar()->monthNamePossessive(month, year, true));
01146 else
01147 buffer.append(calendar()->monthName(month, year, true));
01148 break;
01149 case 'B':
01150 if (d->nounDeclension && d->dateMonthNamePossessive)
01151 buffer.append(calendar()->monthNamePossessive(month, year, false));
01152 else
01153 buffer.append(calendar()->monthName(month, year, false));
01154 break;
01155 case 'd':
01156 buffer.append(calendar()->dayString(pDate, false));
01157 break;
01158 case 'a':
01159 buffer.append(calendar()->weekDayName(pDate, true));
01160 break;
01161 case 'A':
01162 buffer.append(calendar()->weekDayName(pDate, false));
01163 break;
01164 default:
01165 buffer.append(rst.at(format_index));
01166 break;
01167 }
01168 escape = false;
01169 }
01170 }
01171 return buffer;
01172 }
01173
01174 void KLocale::setMainCatalogue(const char *catalog)
01175 {
01176 maincatalogue = catalog;
01177 }
01178
01179 double KLocale::readNumber(const QString &_str, bool * ok) const
01180 {
01181 QString str = _str.stripWhiteSpace();
01182 bool neg = str.find(negativeSign()) == 0;
01183 if (neg)
01184 str.remove( 0, negativeSign().length() );
01185
01186
01187
01188
01189 QString exponentialPart;
01190 int EPos;
01191
01192 EPos = str.find('E', 0, false);
01193
01194 if (EPos != -1)
01195 {
01196 exponentialPart = str.mid(EPos);
01197 str = str.left(EPos);
01198 }
01199
01200 int pos = str.find(decimalSymbol());
01201 QString major;
01202 QString minor;
01203 if ( pos == -1 )
01204 major = str;
01205 else
01206 {
01207 major = str.left(pos);
01208 minor = str.mid(pos + decimalSymbol().length());
01209 }
01210
01211
01212 int thlen = thousandsSeparator().length();
01213 int lastpos = 0;
01214 while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
01215 {
01216
01217 int fromEnd = major.length() - pos;
01218 if ( fromEnd % (3+thlen) != 0
01219 || pos - lastpos > 3
01220 || pos == 0
01221 || (lastpos>0 && pos-lastpos!=3))
01222 {
01223 if (ok) *ok = false;
01224 return 0.0;
01225 }
01226
01227 lastpos = pos;
01228 major.remove( pos, thlen );
01229 }
01230 if (lastpos>0 && major.length()-lastpos!=3)
01231 {
01232 if (ok) *ok = false;
01233 return 0.0;
01234 }
01235
01236 QString tot;
01237 if (neg) tot = '-';
01238
01239 tot += major + '.' + minor + exponentialPart;
01240
01241 return tot.toDouble(ok);
01242 }
01243
01244 double KLocale::readMoney(const QString &_str, bool * ok) const
01245 {
01246 QString str = _str.stripWhiteSpace();
01247 bool neg = false;
01248 bool currencyFound = false;
01249
01250 int pos = str.find(currencySymbol());
01251 if ( pos == 0 || pos == (int) str.length()-1 )
01252 {
01253 str.remove(pos,currencySymbol().length());
01254 str = str.stripWhiteSpace();
01255 currencyFound = true;
01256 }
01257 if (str.isEmpty())
01258 {
01259 if (ok) *ok = false;
01260 return 0;
01261 }
01262
01263
01264 if (negativeMonetarySignPosition() == ParensAround)
01265 {
01266 if (str[0] == '(' && str[str.length()-1] == ')')
01267 {
01268 neg = true;
01269 str.remove(str.length()-1,1);
01270 str.remove(0,1);
01271 }
01272 }
01273 else
01274 {
01275 int i1 = str.find(negativeSign());
01276 if ( i1 == 0 || i1 == (int) str.length()-1 )
01277 {
01278 neg = true;
01279 str.remove(i1,negativeSign().length());
01280 }
01281 }
01282 if (neg) str = str.stripWhiteSpace();
01283
01284
01285
01286 if ( !currencyFound )
01287 {
01288 pos = str.find(currencySymbol());
01289 if ( pos == 0 || pos == (int) str.length()-1 )
01290 {
01291 str.remove(pos,currencySymbol().length());
01292 str = str.stripWhiteSpace();
01293 }
01294 }
01295
01296
01297 pos = str.find(monetaryDecimalSymbol());
01298 QString major;
01299 QString minior;
01300 if (pos == -1)
01301 major = str;
01302 else
01303 {
01304 major = str.left(pos);
01305 minior = str.mid(pos + monetaryDecimalSymbol().length());
01306 }
01307
01308
01309 int thlen = monetaryThousandsSeparator().length();
01310 int lastpos = 0;
01311 while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
01312 {
01313
01314 int fromEnd = major.length() - pos;
01315 if ( fromEnd % (3+thlen) != 0
01316 || pos - lastpos > 3
01317 || pos == 0
01318 || (lastpos>0 && pos-lastpos!=3))
01319 {
01320 if (ok) *ok = false;
01321 return 0.0;
01322 }
01323 lastpos = pos;
01324 major.remove( pos, thlen );
01325 }
01326 if (lastpos>0 && major.length()-lastpos!=3)
01327 {
01328 if (ok) *ok = false;
01329 return 0.0;
01330 }
01331
01332 QString tot;
01333 if (neg) tot = '-';
01334 tot += major + '.' + minior;
01335 return tot.toDouble(ok);
01336 }
01337
01344 static int readInt(const QString &str, uint &pos)
01345 {
01346 if (!str.at(pos).isDigit()) return -1;
01347 int result = 0;
01348 for (; str.length() > pos && str.at(pos).isDigit(); pos++)
01349 {
01350 result *= 10;
01351 result += str.at(pos).digitValue();
01352 }
01353
01354 return result;
01355 }
01356
01357 QDate KLocale::readDate(const QString &intstr, bool* ok) const
01358 {
01359 QDate date;
01360 date = readDate(intstr, ShortFormat, ok);
01361 if (date.isValid()) return date;
01362 return readDate(intstr, NormalFormat, ok);
01363 }
01364
01365 QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
01366 {
01367 QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
01368 return readDate( intstr, fmt, ok );
01369 }
01370
01371 QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
01372 {
01373
01374 QString str = intstr.simplifyWhiteSpace().lower