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