1
// -*- c-basic-offset: 2 -*-
2
/* This file is part of the KDE libraries
3
Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
4
Copyright (c) 1999 Preston Brown <pbrown@kde.org>
5
Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
6
Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
8
This library is free software; you can redistribute it and/or
9
modify it under the terms of the GNU Library General Public
10
License as published by the Free Software Foundation; either
11
version 2 of the License, or (at your option) any later version.
13
This library is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
Library General Public License for more details.
18
You should have received a copy of the GNU Library General Public License
19
along with this library; see the file COPYING.LIB. If not, write to
20
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21
Boston, MA 02110-1301, USA.
26
#include <stdlib.h> // getenv
28
#include <qtextcodec.h>
31
#include <qdatetime.h>
32
#include <qfileinfo.h>
35
#include "kcatalogue.h"
37
#include "kstandarddirs.h"
38
#include "ksimpleconfig.h"
39
#include "kinstance.h"
42
#include "kcalendarsystem.h"
43
#include "kcalendarsystemfactory.h"
50
static const char * const SYSTEM_MESSAGES = "kdelibs";
52
static const char *maincatalogue = 0;
59
bool dateMonthNamePossessive;
60
QStringList languageList;
61
QStringList catalogNames; // list of all catalogs (regardless of language)
62
QValueList<KCatalogue> catalogues; // list of all loaded catalogs, contains one instance per catalog name and language
64
QTextCodec * codecForEncoding;
67
int /*QPrinter::PageSize*/ pageSize;
68
KLocale::MeasureSystem measureSystem;
69
QStringList langTwoAlpha;
73
KCalendarSystem * calendar;
74
bool utf8FileEncoding;
77
char win32SystemEncoding[3+7]; //"cp " + lang ID
81
static KLocale *this_klocale = 0;
83
KLocale::KLocale( const QString & catalog, KConfig * config )
85
d = new KLocalePrivate;
89
d->formatInited = false;
92
initFileNameEncoding(0);
94
KConfig *cfg = d->config;
96
if (!cfg) cfg = KGlobal::instance()->config();
100
d->appName = catalog;
101
initLanguageList( cfg, config == 0);
102
initMainCatalogues(catalog);
105
QString KLocale::_initLanguage(KConfigBase *config)
109
// ### HPB Why this cast??
110
this_klocale->initLanguageList((KConfig *) config, true);
111
// todo: adapt current catalog list: remove unused languages, insert main catalogs, if not already found
112
return this_klocale->language();
114
return QString::null;
117
void KLocale::initMainCatalogues(const QString & catalog)
119
// Use the first non-null string.
120
QString mainCatalogue = catalog;
122
mainCatalogue = QString::fromLatin1(maincatalogue);
124
if (mainCatalogue.isEmpty()) {
125
kdDebug(173) << "KLocale instance created called without valid "
126
<< "catalog! Give an argument or call setMainCatalogue "
127
<< "before init" << endl;
130
// do not use insertCatalogue here, that would already trigger updateCatalogs
131
d->catalogNames.append( mainCatalogue ); // application catalog
132
d->catalogNames.append( SYSTEM_MESSAGES ); // always include kdelibs.mo
133
d->catalogNames.append( "kio" ); // always include kio.mo
134
updateCatalogues(); // evaluate this for all languages
138
void KLocale::initLanguageList(KConfig * config, bool useEnv)
140
KConfigGroupSaver saver(config, "Locale");
142
m_country = config->readEntry( "Country" );
143
if ( m_country.isEmpty() )
144
m_country = defaultCountry();
146
// Reset the list and add the new languages
147
QStringList languageList;
149
languageList += QStringList::split
150
(':', QFile::decodeName( ::getenv("KDE_LANG") ));
152
languageList += config->readListEntry("Language", ':');
154
// same order as setlocale use
157
// HPB: Only run splitLocale on the environment variables..
160
langs << QFile::decodeName( ::getenv("LC_ALL") );
161
langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
162
langs << QFile::decodeName( ::getenv("LANG") );
164
for ( QStringList::Iterator it = langs.begin();
168
QString ln, ct, chrset;
169
splitLocale(*it, ln, ct, chrset);
172
langs.insert(it, ln + '_' + ct);
173
if (!chrset.isEmpty())
174
langs.insert(it, ln + '_' + ct + '.' + chrset);
177
langs.insert(it, ln);
180
languageList += langs;
183
// now we have a language list -- let's use the first OK language
184
setLanguage( languageList );
187
void KLocale::initPluralTypes()
189
for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
190
it != d->catalogues.end();
193
QString language = (*it).language();
194
int pt = pluralType( language );
195
(*it).setPluralType( pt );
200
int KLocale::pluralType( const QString & language )
202
for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
203
it != d->catalogues.end();
206
if ( ((*it).name() == SYSTEM_MESSAGES ) && ((*it).language() == language )) {
207
return pluralType( *it );
210
// kdelibs.mo does not seem to exist for this language
214
int KLocale::pluralType( const KCatalogue& catalog )
216
const char* pluralFormString =
217
I18N_NOOP("_: Dear translator, please do not translate this string "
218
"in any form, but pick the _right_ value out of "
219
"NoPlural/TwoForms/French... If not sure what to do mail "
220
"thd@kde.org and coolo@kde.org, they will tell you. "
221
"Better leave that out if unsure, the programs will "
222
"crash!!\nDefinition of PluralForm - to be set by the "
223
"translator of kdelibs.po");
224
QString pf (catalog.translate( pluralFormString));
225
if ( pf.isEmpty() ) {
228
else if ( pf == "NoPlural" )
230
else if ( pf == "TwoForms" )
232
else if ( pf == "French" )
234
else if ( pf == "OneTwoRest" )
236
else if ( pf == "Russian" )
238
else if ( pf == "Polish" )
240
else if ( pf == "Slovenian" )
242
else if ( pf == "Lithuanian" )
244
else if ( pf == "Czech" )
246
else if ( pf == "Slovak" )
248
else if ( pf == "Maltese" )
250
else if ( pf == "Arabic" )
252
else if ( pf == "Balcan" )
254
else if ( pf == "Macedonian" )
256
else if ( pf == "Gaeilge" )
259
kdWarning(173) << "Definition of PluralForm is none of "
274
<< "Maltese: " << pf << endl;
279
void KLocale::doFormatInit() const
281
if ( d->formatInited ) return;
283
KLocale * that = const_cast<KLocale *>(this);
286
d->formatInited = true;
289
void KLocale::initFormat()
291
KConfig *config = d->config;
292
if (!config) config = KGlobal::instance()->config();
295
kdDebug(173) << "KLocale::initFormat" << endl;
297
// make sure the config files are read using the correct locale
298
// ### Why not add a KConfigBase::setLocale( const KLocale * )?
299
// ### Then we could remove this hack
300
KLocale *lsave = KGlobal::_locale;
301
KGlobal::_locale = this;
303
KConfigGroupSaver saver(config, "Locale");
305
KSimpleConfig entry(locate("locale",
306
QString::fromLatin1("l10n/%1/entry.desktop")
307
.arg(m_country)), true);
308
entry.setGroup("KCM Locale");
311
#define readConfigEntry(key, default, save) \
312
save = entry.readEntry(key, QString::fromLatin1(default)); \
313
save = config->readEntry(key, save);
315
#define readConfigNumEntry(key, default, save, type) \
316
save = (type)entry.readNumEntry(key, default); \
317
save = (type)config->readNumEntry(key, save);
319
#define readConfigBoolEntry(key, default, save) \
320
save = entry.readBoolEntry(key, default); \
321
save = config->readBoolEntry(key, save);
323
readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
324
readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
325
m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null );
326
//kdDebug(173) << "m_thousandsSeparator=" << m_thousandsSeparator << endl;
328
readConfigEntry("PositiveSign", "", m_positiveSign);
329
readConfigEntry("NegativeSign", "-", m_negativeSign);
332
readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
333
readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
334
readConfigEntry("MonetaryThousandsSeparator", ",",
335
m_monetaryThousandsSeparator);
336
m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null);
338
readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
339
readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
340
m_positivePrefixCurrencySymbol);
341
readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
342
m_negativePrefixCurrencySymbol);
343
readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
344
m_positiveMonetarySignPosition, SignPosition);
345
readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
346
m_negativeMonetarySignPosition, SignPosition);
350
readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
351
readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
352
readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
353
readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
356
readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
357
readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
359
readConfigEntry("CalendarSystem", "gregorian", d->calendarType);
361
d->calendar = 0; // ### HPB Is this the correct place?
364
//Precedence here is l10n / i18n / config file
365
KSimpleConfig language(locate("locale",
366
QString::fromLatin1("%1/entry.desktop")
367
.arg(m_language)), true);
368
language.setGroup("KCM Locale");
369
#define read3ConfigBoolEntry(key, default, save) \
370
save = entry.readBoolEntry(key, default); \
371
save = language.readBoolEntry(key, save); \
372
save = config->readBoolEntry(key, save);
374
read3ConfigBoolEntry("NounDeclension", false, d->nounDeclension);
375
read3ConfigBoolEntry("DateMonthNamePossessive", false,
376
d->dateMonthNamePossessive);
379
KGlobal::_locale = lsave;
382
bool KLocale::setCountry(const QString & country)
384
// Check if the file exists too??
385
if ( country.isEmpty() )
390
d->formatInited = false;
395
QString KLocale::catalogueFileName(const QString & language,
396
const KCatalogue & catalog)
398
QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
400
.arg( catalog.name() );
402
return locate( "locale", path );
405
bool KLocale::setLanguage(const QString & language)
407
if ( d->languageList.contains( language ) ) {
408
d->languageList.remove( language );
410
d->languageList.prepend( language ); // let us consider this language to be the most important one
412
m_language = language; // remember main language for shortcut evaluation
414
// important when called from the outside and harmless when called before populating the
418
d->formatInited = false;
420
return true; // Maybe the mo-files for this language are empty, but in principle we can speak all languages
423
bool KLocale::setLanguage(const QStringList & languages)
425
QStringList languageList( languages );
426
// This list might contain
427
// 1) some empty strings that we have to eliminate
428
// 2) duplicate entries like in de:fr:de, where we have to keep the first occurrance of a language in order
429
// to preserve the order of precenence of the user => iterate backwards
430
// 3) languages into which the application is not translated. For those languages we should not even load kdelibs.mo or kio.po.
431
// these langugage have to be dropped. Otherwise we get strange side effects, e.g. with Hebrew:
432
// the right/left switch for languages that write from
433
// right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have kdelibs.mo
434
// but nothing from appname.mo, you get a mostly English app with layout from right to left.
435
// That was considered to be a bug by the Hebrew translators.
436
for( QStringList::Iterator it = languageList.fromLast();
437
it != languageList.begin(); --it )
439
// kdDebug() << "checking " << (*it) << endl;
440
bool bIsTranslated = isApplicationTranslatedInto( *it );
441
if ( languageList.contains(*it) > 1 || (*it).isEmpty() || (!bIsTranslated) ) {
442
// kdDebug() << "removing " << (*it) << endl;
443
it = languageList.remove( it );
446
// now this has left the first element of the list unchecked.
447
// The question why this is the case is left as an exercise for the reader...
448
// Besides the list might have been empty all the way, so check that too.
449
if ( languageList.begin() != languageList.end() ) {
450
QStringList::Iterator it = languageList.begin(); // now pointing to the first element
451
// kdDebug() << "checking " << (*it) << endl;
452
if( (*it).isEmpty() || !(isApplicationTranslatedInto( *it )) ) {
453
// kdDebug() << "removing " << (*it) << endl;
454
languageList.remove( it ); // that's what the iterator was for...
458
if ( languageList.isEmpty() ) {
459
// user picked no language, so we assume he/she speaks English.
460
languageList.append( defaultLanguage() );
462
m_language = languageList.first(); // keep this for shortcut evaluations
464
d->languageList = languageList; // keep this new list of languages to use
465
d->langTwoAlpha.clear(); // Flush cache
467
// important when called from the outside and harmless when called before populating the
471
return true; // we found something. Maybe it's only English, but we found something
474
bool KLocale::isApplicationTranslatedInto( const QString & language)
476
if ( language.isEmpty() ) {
480
if ( language == defaultLanguage() ) {
481
// en_us is always "installed"
485
QString appName = d->appName;
487
appName = QString::fromLatin1(maincatalogue);
489
// sorry, catalogueFileName requires catalog object,k which we do not have here
490
// path finding was supposed to be moved completely to KCatalogue. The interface cannot
491
// be changed that far during deep freeze. So in order to fix the bug now, we have
492
// duplicated code for file path evaluation. Cleanup will follow later. We could have e.g.
493
// a static method in KCataloge that can translate between these file names.
495
QString sFileName = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
498
// kdDebug() << "isApplicationTranslatedInto: filename " << sFileName << endl;
500
QString sAbsFileName = locate( "locale", sFileName );
501
// kdDebug() << "isApplicationTranslatedInto: absname " << sAbsFileName << endl;
502
return ! sAbsFileName.isEmpty();
505
void KLocale::splitLocale(const QString & aStr,
512
// just in case, there is another language appended
513
int f = str.find(':');
517
country = QString::null;
518
chrset = QString::null;
519
language = QString::null;
524
chrset = str.mid(f + 1);
531
country = str.mid(f + 1);
538
QString KLocale::language() const
543
QString KLocale::country() const
548
QString KLocale::monthName(int i, bool shortName) const
553
case 1: return translate("January", "Jan");
554
case 2: return translate("February", "Feb");
555
case 3: return translate("March", "Mar");
556
case 4: return translate("April", "Apr");
557
case 5: return translate("May short", "May");
558
case 6: return translate("June", "Jun");
559
case 7: return translate("July", "Jul");
560
case 8: return translate("August", "Aug");
561
case 9: return translate("September", "Sep");
562
case 10: return translate("October", "Oct");
563
case 11: return translate("November", "Nov");
564
case 12: return translate("December", "Dec");
569
case 1: return translate("January");
570
case 2: return translate("February");
571
case 3: return translate("March");
572
case 4: return translate("April");
573
case 5: return translate("May long", "May");
574
case 6: return translate("June");
575
case 7: return translate("July");
576
case 8: return translate("August");
577
case 9: return translate("September");
578
case 10: return translate("October");
579
case 11: return translate("November");
580
case 12: return translate("December");
583
return QString::null;
586
QString KLocale::monthNamePossessive(int i, bool shortName) const
591
case 1: return translate("of January", "of Jan");
592
case 2: return translate("of February", "of Feb");
593
case 3: return translate("of March", "of Mar");
594
case 4: return translate("of April", "of Apr");
595
case 5: return translate("of May short", "of May");
596
case 6: return translate("of June", "of Jun");
597
case 7: return translate("of July", "of Jul");
598
case 8: return translate("of August", "of Aug");
599
case 9: return translate("of September", "of Sep");
600
case 10: return translate("of October", "of Oct");
601
case 11: return translate("of November", "of Nov");
602
case 12: return translate("of December", "of Dec");
607
case 1: return translate("of January");
608
case 2: return translate("of February");
609
case 3: return translate("of March");
610
case 4: return translate("of April");
611
case 5: return translate("of May long", "of May");
612
case 6: return translate("of June");
613
case 7: return translate("of July");
614
case 8: return translate("of August");
615
case 9: return translate("of September");
616
case 10: return translate("of October");
617
case 11: return translate("of November");
618
case 12: return translate("of December");
621
return QString::null;
624
QString KLocale::weekDayName (int i, bool shortName) const
626
return calendar()->weekDayName(i, shortName);
629
void KLocale::insertCatalogue( const QString & catalog )
631
if ( !d->catalogNames.contains( catalog) ) {
632
d->catalogNames.append( catalog );
634
updateCatalogues( ); // evaluate the changed list and generate the neccessary KCatalog objects
637
void KLocale::updateCatalogues( )
639
// some changes have occured. Maybe we have learned or forgotten some languages.
640
// Maybe the language precedence has changed.
641
// Maybe we have learned or forgotten some catalog names.
642
// Now examine the list of KCatalogue objects and change it according to the new circumstances.
644
// this could be optimized: try to reuse old KCatalog objects, but remember that the order of
645
// catalogs might have changed: e.g. in this fashion
646
// 1) move all catalogs into a temporary list
647
// 2) iterate over all languages and catalog names
648
// 3.1) pick the catalog from the saved list, if it already exists
649
// 3.2) else create a new catalog.
650
// but we will do this later.
652
for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
653
it != d->catalogues.end(); )
655
it = d->catalogues.remove(it);
658
// now iterate over all languages and all wanted catalog names and append or create them in the right order
659
// the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs de/kio etc.
660
// and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be in trouble with a language
661
// sequende nds,en_US, de. In this case en_US must hide everything below in the language list.
662
for ( QStringList::ConstIterator itLangs = d->languageList.begin();
663
itLangs != d->languageList.end(); ++itLangs)
665
for ( QStringList::ConstIterator itNames = d->catalogNames.begin();
666
itNames != d->catalogNames.end(); ++itNames)
668
KCatalogue cat( *itNames, *itLangs ); // create Catalog for this name and this language
669
d->catalogues.append( cat );
672
initPluralTypes(); // evaluate the plural type for all languages and remember this in each KCatalogue
678
void KLocale::removeCatalogue(const QString &catalog)
680
if ( d->catalogNames.contains( catalog )) {
681
d->catalogNames.remove( catalog );
682
if (KGlobal::_instance)
683
updateCatalogues(); // walk through the KCatalogue instances and weed out everything we no longer need
687
void KLocale::setActiveCatalogue(const QString &catalog)
689
if ( d->catalogNames.contains( catalog ) ) {
690
d->catalogNames.remove( catalog );
691
d->catalogNames.prepend( catalog );
692
updateCatalogues(); // walk through the KCatalogue instances and adapt to the new order
704
QString KLocale::translate_priv(const char *msgid,
705
const char *fallback,
706
const char **translated,
707
int* pluralType ) const
710
*pluralType = -1; // unless we find something more precise
712
if (!msgid || !msgid[0])
714
kdWarning() << "KLocale: trying to look up \"\" in catalog. "
715
<< "Fix the program" << endl;
716
return QString::null;
719
if ( useDefaultLanguage() ) { // shortcut evaluation if en_US is main language: do not consult the catalogs
720
return QString::fromUtf8( fallback );
723
for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
724
it != d->catalogues.end();
727
// shortcut evaluation: once we have arrived at en_US (default language) we cannot consult
728
// the catalog as it will not have an assiciated mo-file. For this default language we can
729
// immediately pick the fallback string.
730
if ( (*it).language() == defaultLanguage() ) {
731
return QString::fromUtf8( fallback );
734
const char * text = (*it).translate( msgid );
743
*pluralType = (*it).pluralType(); // remember the plural type information from the catalog that was used
745
return QString::fromUtf8( text );
749
// Always use UTF-8 if the string was not found
750
return QString::fromUtf8( fallback );
753
QString KLocale::translate(const char* msgid) const
755
return translate_priv(msgid, msgid);
758
QString KLocale::translate( const char *index, const char *fallback) const
760
if (!index || !index[0] || !fallback || !fallback[0])
762
kdDebug(173) << "KLocale: trying to look up \"\" in catalog. "
763
<< "Fix the program" << endl;
764
return QString::null;
767
if ( useDefaultLanguage() )
768
return QString::fromUtf8( fallback );
770
char *newstring = new char[strlen(index) + strlen(fallback) + 5];
771
sprintf(newstring, "_: %s\n%s", index, fallback);
772
// as copying QString is very fast, it looks slower as it is ;/
773
QString r = translate_priv(newstring, fallback);
779
static QString put_n_in(const QString &orig, unsigned long n)
782
int index = ret.find("%n");
785
ret.replace(index, 2, QString::number(n));
789
#define EXPECT_LENGTH(x) \
790
if (forms.count() != x) { \
791
kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
792
return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
794
QString KLocale::translate( const char *singular, const char *plural,
795
unsigned long n ) const
797
if (!singular || !singular[0] || !plural || !plural[0])
799
kdWarning() << "KLocale: trying to look up \"\" in catalog. "
800
<< "Fix the program" << endl;
801
return QString::null;
804
char *newstring = new char[strlen(singular) + strlen(plural) + 6];
805
sprintf(newstring, "_n: %s\n%s", singular, plural);
806
// as copying QString is very fast, it looks slower as it is ;/
808
QString r = translate_priv(newstring, 0, 0, &pluralType);
811
if ( r.isEmpty() || useDefaultLanguage() || pluralType == -1) {
813
return put_n_in( QString::fromUtf8( singular ), n );
815
QString tmp = QString::fromUtf8( plural );
817
if (tmp.find("%n") == -1) {
818
kdDebug() << "the message for i18n should contain a '%n'! " << plural << endl;
821
return put_n_in( tmp, n );
825
QStringList forms = QStringList::split( "\n", r, false );
826
switch ( pluralType ) {
829
return put_n_in( forms[0], n);
833
return put_n_in( forms[0], n);
835
return put_n_in( forms[1], n);
838
if ( n == 1 || n == 0 )
839
return put_n_in( forms[0], n);
841
return put_n_in( forms[1], n);
842
case 3: // OneTwoRest
845
return put_n_in( forms[0], n);
847
return put_n_in( forms[1], n);
849
return put_n_in( forms[2], n);
850
case 4: // Russian, corrected by mok
852
if ( n%10 == 1 && n%100 != 11)
853
return put_n_in( forms[0], n); // odin fail
854
else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
855
return put_n_in( forms[1], n); // dva faila
857
return put_n_in( forms[2], n); // desyat' failov
861
return put_n_in( forms[0], n);
862
else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
863
return put_n_in( forms[1], n);
865
return put_n_in( forms[2], n);
869
return put_n_in( forms[1], n); // ena datoteka
870
else if ( n%100 == 2 )
871
return put_n_in( forms[2], n); // dve datoteki
872
else if ( n%100 == 3 || n%100 == 4 )
873
return put_n_in( forms[3], n); // tri datoteke
875
return put_n_in( forms[0], n); // sto datotek
876
case 7: // Lithuanian
878
if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
879
return put_n_in( forms[2], n);
880
else if ( n%10 == 1 )
881
return put_n_in( forms[0], n);
883
return put_n_in( forms[1], n);
884
case 8: // Czech - use modern form which is equivalent to Slovak
888
return put_n_in( forms[0], n);
889
else if (( n >= 2 ) && ( n <= 4 ))
890
return put_n_in( forms[1], n);
892
return put_n_in( forms[2], n);
896
return put_n_in( forms[0], n );
897
else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
898
return put_n_in( forms[1], n );
899
else if ( n%100 > 10 && n%100 < 20 )
900
return put_n_in( forms[2], n );
902
return put_n_in( forms[3], n );
906
return put_n_in(forms[0], n);
908
return put_n_in(forms[1], n);
910
return put_n_in(forms[2], n);
912
return put_n_in(forms[3], n);
915
if (n != 11 && n % 10 == 1)
916
return put_n_in(forms[0], n);
917
else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
918
return put_n_in(forms[1], n);
920
return put_n_in(forms[2], n);
921
case 13: // Macedonian
924
return put_n_in(forms[0], n);
925
else if (n % 10 == 2)
926
return put_n_in(forms[1], n);
928
return put_n_in(forms[2], n);
931
if (n == 1) // "ceann amhain"
932
return put_n_in(forms[0], n);
933
else if (n == 2) // "dha cheann"
934
return put_n_in(forms[1], n);
935
else if (n < 7) // "%n cinn"
936
return put_n_in(forms[2], n);
937
else if (n < 11) // "%n gcinn"
938
return put_n_in(forms[3], n);
940
return put_n_in(forms[4], n);
942
kdFatal() << "The function should have been returned in another way\n";
944
return QString::null;
947
QString KLocale::translateQt( const char *context, const char *source,
948
const char *message) const
950
if (!source || !source[0]) {
951
kdWarning() << "KLocale: trying to look up \"\" in catalog. "
952
<< "Fix the program" << endl;
953
return QString::null;
956
if ( useDefaultLanguage() ) {
957
return QString::null;
961
const char *translation = 0;
964
if ( message && message[0]) {
965
char *newstring = new char[strlen(source) + strlen(message) + 5];
966
sprintf(newstring, "_: %s\n%s", source, message);
967
const char *translation = 0;
968
// as copying QString is very fast, it looks slower as it is ;/
969
r = translate_priv(newstring, source, &translation);
975
if ( context && context[0] && message && message[0]) {
976
newstring = new char[strlen(context) + strlen(message) + 5];
977
sprintf(newstring, "_: %s\n%s", context, message);
978
// as copying QString is very fast, it looks slower as it is ;/
979
r = translate_priv(newstring, source, &translation);
985
r = translate_priv(source, source, &translation);
988
return QString::null;
991
bool KLocale::nounDeclension() const
994
return d->nounDeclension;
997
bool KLocale::dateMonthNamePossessive() const
1000
return d->dateMonthNamePossessive;
1003
int KLocale::weekStartDay() const
1006
return d->weekStartDay;
1009
bool KLocale::weekStartsMonday() const //deprecated
1012
return (d->weekStartDay==1);
1015
QString KLocale::decimalSymbol() const
1018
return m_decimalSymbol;
1021
QString KLocale::thousandsSeparator() const
1024
return m_thousandsSeparator;
1027
QString KLocale::currencySymbol() const
1030
return m_currencySymbol;
1033
QString KLocale::monetaryDecimalSymbol() const
1036
return m_monetaryDecimalSymbol;
1039
QString KLocale::monetaryThousandsSeparator() const
1042
return m_monetaryThousandsSeparator;
1045
QString KLocale::positiveSign() const
1048
return m_positiveSign;
1051
QString KLocale::negativeSign() const
1054
return m_negativeSign;
1057
int KLocale::fracDigits() const
1060
return m_fracDigits;
1063
bool KLocale::positivePrefixCurrencySymbol() const
1066
return m_positivePrefixCurrencySymbol;
1069
bool KLocale::negativePrefixCurrencySymbol() const
1072
return m_negativePrefixCurrencySymbol;
1075
KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
1078
return m_positiveMonetarySignPosition;
1081
KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
1084
return m_negativeMonetarySignPosition;
1087
static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
1089
for ( uint l = 0; l < s.length(); l++ )
1090
buffer[index++] = s.at( l );
1093
static inline void put_it_in( QChar *buffer, uint& index, int number )
1095
buffer[index++] = number / 10 + '0';
1096
buffer[index++] = number % 10 + '0';
1099
// insert (thousands)-"separator"s into the non-fractional part of str
1100
static void _insertSeparator(QString &str, const QString &separator,
1101
const QString &decimalSymbol)
1103
// leave fractional part untouched
1104
QString mainPart = str.section(decimalSymbol, 0, 0);
1105
QString fracPart = str.section(decimalSymbol, 1, 1,
1106
QString::SectionIncludeLeadingSep);
1108
for (int pos = mainPart.length() - 3; pos > 0; pos -= 3)
1109
mainPart.insert(pos, separator);
1111
str = mainPart + fracPart;
1114
QString KLocale::formatMoney(double num,
1115
const QString & symbol,
1116
int precision) const
1119
QString currency = symbol.isNull()
1122
if (precision < 0) precision = fracDigits();
1124
// the number itself
1126
QString res = QString::number(neg?-num:num, 'f', precision);
1128
// Replace dot with locale decimal separator
1129
res.replace(QChar('.'), monetaryDecimalSymbol());
1131
// Insert the thousand separators
1132
_insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
1134
// set some variables we need later
1136
? negativeMonetarySignPosition()
1137
: positiveMonetarySignPosition();
1148
case BeforeQuantityMoney:
1151
case AfterQuantityMoney:
1155
currency.prepend(sign);
1158
currency.append(sign);
1162
if (neg?negativePrefixCurrencySymbol():
1163
positivePrefixCurrencySymbol())
1166
res.prepend(currency);
1169
res.append (currency);
1175
QString KLocale::formatMoney(const QString &numStr) const
1177
return formatMoney(numStr.toDouble());
1180
QString KLocale::formatNumber(double num, int precision) const
1182
if (precision == -1) precision = 2;
1183
// no need to round since QString::number does this for us
1184
return formatNumber(QString::number(num, 'f', precision), false, 0);
1187
QString KLocale::formatLong(long num) const
1189
return formatNumber((double)num, 0);
1192
QString KLocale::formatNumber(const QString &numStr) const
1194
return formatNumber(numStr, true, 2);
1197
// increase the digit at 'position' by one
1198
static void _inc_by_one(QString &str, int position)
1200
for (int i = position; i >= 0; i--)
1202
char last_char = str[i].latin1();
1234
if (i == 0) str.prepend('1');
1243
// Cut off if more digits in fractional part than 'precision'
1244
static void _round(QString &str, int precision)
1246
int decimalSymbolPos = str.find('.');
1248
if (decimalSymbolPos == -1)
1249
if (precision == 0) return;
1250
else if (precision > 0) // add dot if missing (and needed)
1253
decimalSymbolPos = str.length() - 1;
1256
// fill up with more than enough zeroes (in case fractional part too short)
1257
str.append(QString().fill('0', precision));
1259
// Now decide whether to round up or down
1260
char last_char = str[decimalSymbolPos + precision + 1].latin1();
1268
// nothing to do, rounding down
1275
_inc_by_one(str, decimalSymbolPos + precision);
1281
decimalSymbolPos = str.find('.');
1282
str.truncate(decimalSymbolPos + precision + 1);
1284
// if precision == 0 delete also '.'
1285
if (precision == 0) str = str.section('.', 0, 0);
1288
QString KLocale::formatNumber(const QString &numStr, bool round,
1289
int precision) const
1291
QString tmpString = numStr;
1292
if ((round && precision < 0) ||
1293
! QRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
1297
// Skip the sign (for now)
1298
bool neg = (tmpString[0] == '-');
1299
if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
1301
// Split off exponential part (including 'e'-symbol)
1302
QString mantString = tmpString.section('e', 0, 0,
1303
QString::SectionCaseInsensitiveSeps);
1304
QString expString = tmpString.section('e', 1, 1,
1305
QString::SectionCaseInsensitiveSeps |
1306
QString::SectionIncludeLeadingSep);
1308
if (round) _round(mantString, precision);
1310
// Replace dot with locale decimal separator
1311
mantString.replace(QChar('.'), decimalSymbol());
1313
// Insert the thousand separators
1314
_insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
1316
// How can we know where we should put the sign?
1317
mantString.prepend(neg?negativeSign():positiveSign());
1319
return mantString + expString;
1322
QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
1324
const QString rst = shortFormat?dateFormatShort():dateFormat();
1328
if ( ! pDate.isValid() ) return buffer;
1330
bool escape = false;
1332
int year = calendar()->year(pDate);
1333
int month = calendar()->month(pDate);
1335
for ( uint format_index = 0; format_index < rst.length(); ++format_index )
1339
if ( rst.at( format_index ).unicode() == '%' )
1342
buffer.append(rst.at(format_index));
1346
switch ( rst.at( format_index ).unicode() )
1352
buffer.append(calendar()->yearString(pDate, false));
1355
buffer.append(calendar()->yearString(pDate, true));
1358
buffer.append(calendar()->monthString(pDate, true));
1361
buffer.append(calendar()->dayString(pDate, true));
1364
buffer.append(calendar()->monthString(pDate, false));
1367
if (d->nounDeclension && d->dateMonthNamePossessive)
1368
buffer.append(calendar()->monthNamePossessive(month, year, true));
1370
buffer.append(calendar()->monthName(month, year, true));
1373
if (d->nounDeclension && d->dateMonthNamePossessive)
1374
buffer.append(calendar()->monthNamePossessive(month, year, false));
1376
buffer.append(calendar()->monthName(month, year, false));
1379
buffer.append(calendar()->dayString(pDate, false));
1382
buffer.append(calendar()->weekDayName(pDate, true));
1385
buffer.append(calendar()->weekDayName(pDate, false));
1388
buffer.append(rst.at(format_index));
1397
void KLocale::setMainCatalogue(const char *catalog)
1399
maincatalogue = catalog;
1402
double KLocale::readNumber(const QString &_str, bool * ok) const
1404
QString str = _str.stripWhiteSpace();
1405
bool neg = str.find(negativeSign()) == 0;
1407
str.remove( 0, negativeSign().length() );
1409
/* will hold the scientific notation portion of the number.
1410
Example, with 2.34E+23, exponentialPart == "E+23"
1412
QString exponentialPart;
1415
EPos = str.find('E', 0, false);
1419
exponentialPart = str.mid(EPos);
1420
str = str.left(EPos);
1423
int pos = str.find(decimalSymbol());
1430
major = str.left(pos);
1431
minor = str.mid(pos + decimalSymbol().length());
1434
// Remove thousand separators
1435
int thlen = thousandsSeparator().length();
1437
while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
1439
// e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
1440
int fromEnd = major.length() - pos;
1441
if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
1442
|| pos - lastpos > 3 // More than 3 digits between two separators -> error
1443
|| pos == 0 // Can't start with a separator
1444
|| (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators
1446
if (ok) *ok = false;
1451
major.remove( pos, thlen );
1453
if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator
1455
if (ok) *ok = false;
1462
tot += major + '.' + minor + exponentialPart;
1464
return tot.toDouble(ok);
1467
double KLocale::readMoney(const QString &_str, bool * ok) const
1469
QString str = _str.stripWhiteSpace();
1471
bool currencyFound = false;
1472
QString symbol = currencySymbol();
1473
// First try removing currency symbol from either end
1474
int pos = str.find(symbol);
1475
if ( pos == 0 || pos == (int) str.length()-symbol.length() )
1477
str.remove(pos,symbol.length());
1478
str = str.stripWhiteSpace();
1479
currencyFound = true;
1483
if (ok) *ok = false;
1486
// Then try removing negative sign from either end
1487
// (with a special case for parenthesis)
1488
if (negativeMonetarySignPosition() == ParensAround)
1490
if (str[0] == '(' && str[str.length()-1] == ')')
1493
str.remove(str.length()-1,1);
1499
int i1 = str.find(negativeSign());
1500
if ( i1 == 0 || i1 == (int) str.length()-1 )
1503
str.remove(i1,negativeSign().length());
1506
if (neg) str = str.stripWhiteSpace();
1508
// Finally try again for the currency symbol, if we didn't find
1509
// it already (because of the negative sign being in the way).
1510
if ( !currencyFound )
1512
pos = str.find(symbol);
1513
if ( pos == 0 || pos == (int) str.length()-symbol.length() )
1515
str.remove(pos,symbol.length());
1516
str = str.stripWhiteSpace();
1520
// And parse the rest as a number
1521
pos = str.find(monetaryDecimalSymbol());
1528
major = str.left(pos);
1529
minior = str.mid(pos + monetaryDecimalSymbol().length());
1532
// Remove thousand separators
1533
int thlen = monetaryThousandsSeparator().length();
1535
while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
1537
// e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
1538
int fromEnd = major.length() - pos;
1539
if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
1540
|| pos - lastpos > 3 // More than 3 digits between two separators -> error
1541
|| pos == 0 // Can't start with a separator
1542
|| (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators
1544
if (ok) *ok = false;
1548
major.remove( pos, thlen );
1550
if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator
1552
if (ok) *ok = false;
1558
tot += major + '.' + minior;
1559
return tot.toDouble(ok);
1563
* helper function to read integers
1565
* @param pos the position to start at. It will be updated when we parse it.
1566
* @return the integer read in the string, or -1 if no string
1568
static int readInt(const QString &str, uint &pos)
1570
if (!str.at(pos).isDigit()) return -1;
1572
for (; str.length() > pos && str.at(pos).isDigit(); pos++)
1575
result += str.at(pos).digitValue();
1581
QDate KLocale::readDate(const QString &intstr, bool* ok) const
1584
date = readDate(intstr, ShortFormat, ok);
1585
if (date.isValid()) return date;
1586
return readDate(intstr, NormalFormat, ok);
1589
QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
1591
QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
1592
return readDate( intstr, fmt, ok );
1595
QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
1597
//kdDebug() << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl;
1598
QString str = intstr.simplifyWhiteSpace().lower();
1599
int day = -1, month = -1;
1600
// allow the year to be omitted if not in the format
1601
int year = calendar()->year(QDate::currentDate());
1605
int iLength; // Temporary variable used when reading input
1609
while (fmt.length() > fmtpos && str.length() > strpos && !error)
1612
QChar c = fmt.at(fmtpos++);
1615
if (c.isSpace() && str.at(strpos).isSpace())
1617
else if (c != str.at(strpos++))
1623
// remove space at the beginning
1624
if (str.length() > strpos && str.at(strpos).isSpace())
1627
c = fmt.at(fmtpos++);
1635
while (error && (j < 8)) {
1636
QString s = calendar()->weekDayName(j, c == 'a').lower();
1637
int len = s.length();
1638
if (str.mid(strpos, len) == s)
1650
if (d->nounDeclension && d->dateMonthNamePossessive) {
1652
while (error && (j < 13)) {
1653
QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower();
1654
int len = s.length();
1655
if (str.mid(strpos, len) == s) {
1664
while (error && (j < 13)) {
1665
QString s = calendar()->monthName(j, year, c == 'b').lower();
1666
int len = s.length();
1667
if (str.mid(strpos, len) == s) {
1677
day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
1680
error = iLength <= 0;
1685
month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
1688
error = iLength <= 0;
1693
year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
1696
error = iLength <= 0;
1702
/* for a match, we should reach the end of both strings, not just one of
1704
if ( fmt.length() > fmtpos || str.length() > strpos )
1709
//kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl;
1710
if ( year != -1 && month != -1 && day != -1 && !error)
1715
calendar()->setYMD(result, year, month, day);
1721
if (ok) *ok = false;
1722
return QDate(); // invalid date
1726
QTime KLocale::readTime(const QString &intstr, bool *ok) const
1729
_time = readTime(intstr, WithSeconds, ok);
1730
if (_time.isValid()) return _time;
1731
return readTime(intstr, WithoutSeconds, ok);
1734
QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
1736
QString str = intstr.simplifyWhiteSpace().lower();
1737
QString Format = timeFormat().simplifyWhiteSpace();
1738
if (flags & WithoutSeconds)
1739
Format.remove(QRegExp(".%S"));
1741
int hour = -1, minute = -1;
1742
int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0; // don't require seconds
1748
while (Format.length() > Formatpos || str.length() > strpos)
1750
if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
1752
QChar c = Format.at(Formatpos++);
1758
else if (c != str.at(strpos++))
1763
// remove space at the beginning
1764
if (str.length() > strpos && str.at(strpos).isSpace())
1767
c = Format.at(Formatpos++);
1773
s = translate("pm").lower();
1774
int len = s.length();
1775
if (str.mid(strpos, len) == s)
1782
s = translate("am").lower();
1784
if (str.mid(strpos, len) == s) {
1797
hour = readInt(str, strpos);
1798
if (hour < 0 || hour > 23)
1806
hour = readInt(str, strpos);
1807
if (hour < 1 || hour > 12)
1813
minute = readInt(str, strpos);
1814
if (minute < 0 || minute > 59)
1820
second = readInt(str, strpos);
1821
if (second < 0 || second > 59)
1833
return QTime(hour, minute, second);
1836
if (ok) *ok = false;
1837
// ######## KDE4: remove this
1838
return QTime(-1, -1, -1); // return invalid date if it didn't work
1841
//BIC: merge with below
1842
QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
1844
return formatTime( pTime, includeSecs, false );
1847
QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
1849
const QString rst = timeFormat();
1851
// only "pm/am" here can grow, the rest shrinks, but
1852
// I'm rather safe than sorry
1853
QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
1856
bool escape = false;
1859
for ( uint format_index = 0; format_index < rst.length(); format_index++ )
1863
if ( rst.at( format_index ).unicode() == '%' )
1866
buffer[index++] = rst.at( format_index );
1870
switch ( rst.at( format_index ).unicode() )
1873
buffer[index++] = '%';
1876
put_it_in( buffer, index, pTime.hour() );
1880
put_it_in( buffer, index, pTime.hour() );
1882
put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
1885
put_it_in( buffer, index, pTime.minute() );
1889
put_it_in( buffer, index, pTime.second() );
1890
else if ( index > 0 )
1892
// we remove the separator sign before the seconds and
1893
// assume that works everywhere
1899
number = pTime.hour();
1901
// to share the code
1902
if ( rst.at( format_index ).unicode() == 'l' )
1903
number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
1905
buffer[index++] = number / 10 + '0';
1906
buffer[index++] = number % 10 + '0';
1912
if ( pTime.hour() >= 12 )
1913
put_it_in( buffer, index, translate("pm") );
1915
put_it_in( buffer, index, translate("am") );
1919
buffer[index++] = rst.at( format_index );
1925
QString ret( buffer, index );
1927
if ( isDuration ) // eliminate trailing-space due to " %p"
1928
return ret.stripWhiteSpace();
1933
bool KLocale::use12Clock() const
1935
if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
1936
(timeFormat().contains(QString::fromLatin1("%l")) > 0))
1942
QString KLocale::languages() const
1944
return d->languageList.join( QString::fromLatin1(":") );
1947
QStringList KLocale::languageList() const
1949
return d->languageList;
1952
QString KLocale::formatDateTime(const QDateTime &pDateTime,
1954
bool includeSeconds) const
1956
return translate("concatenation of dates and time", "%1 %2")
1957
.arg( formatDate( pDateTime.date(), shortFormat ) )
1958
.arg( formatTime( pDateTime.time(), includeSeconds ) );
1961
QString i18n(const char* text)
1963
register KLocale *instance = KGlobal::locale();
1965
return instance->translate(text);
1966
return QString::fromUtf8(text);
1969
QString i18n(const char* index, const char *text)
1971
register KLocale *instance = KGlobal::locale();
1973
return instance->translate(index, text);
1974
return QString::fromUtf8(text);
1977
QString i18n(const char* singular, const char* plural, unsigned long n)
1979
register KLocale *instance = KGlobal::locale();
1981
return instance->translate(singular, plural, n);
1983
return put_n_in(QString::fromUtf8(singular), n);
1985
return put_n_in(QString::fromUtf8(plural), n);
1988
void KLocale::initInstance()
1990
if (KGlobal::_locale)
1993
KInstance *app = KGlobal::instance();
1995
KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
1997
// only do this for the global instance
1998
QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
2001
kdDebug(173) << "no app name available using KLocale - nothing to do\n";
2004
QString KLocale::langLookup(const QString &fname, const char *rtype)
2008
// assemble the local search paths
2009
const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
2011
// look up the different languages
2012
for (int id=localDoc.count()-1; id >= 0; --id)
2014
QStringList langs = KGlobal::locale()->languageList();
2015
langs.append( "en" );
2016
langs.remove( defaultLanguage() );
2017
QStringList::ConstIterator lang;
2018
for (lang = langs.begin(); lang != langs.end(); ++lang)
2019
search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
2022
// try to locate the file
2023
QStringList::Iterator it;
2024
for (it = search.begin(); it != search.end(); ++it)
2026
kdDebug(173) << "Looking for help in: " << *it << endl;
2028
QFileInfo info(*it);
2029
if (info.exists() && info.isFile() && info.isReadable())
2033
return QString::null;
2036
bool KLocale::useDefaultLanguage() const
2038
return language() == defaultLanguage();
2041
void KLocale::initEncoding(KConfig *)
2043
const int mibDefault = 4; // ISO 8859-1
2045
// This all made more sense when we still had the EncodingEnum config key.
2046
setEncoding( QTextCodec::codecForLocale()->mibEnum() );
2048
if ( !d->codecForEncoding )
2050
kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
2051
setEncoding(mibDefault);
2054
Q_ASSERT( d->codecForEncoding );
2057
void KLocale::initFileNameEncoding(KConfig *)
2059
// If the following environment variable is set, assume all filenames
2060
// are in UTF-8 regardless of the current C locale.
2061
d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0;
2062
if (d->utf8FileEncoding)
2064
QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
2065
QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
2067
// Otherwise, stay with QFile's default filename encoding functions
2068
// which, on Unix platforms, use the locale's codec.
2071
QCString KLocale::encodeFileNameUTF8( const QString & fileName )
2073
return fileName.utf8();
2076
QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
2078
return QString::fromUtf8(localFileName);
2081
void KLocale::setDateFormat(const QString & format)
2084
m_dateFormat = format.stripWhiteSpace();
2087
void KLocale::setDateFormatShort(const QString & format)
2090
m_dateFormatShort = format.stripWhiteSpace();
2093
void KLocale::setDateMonthNamePossessive(bool possessive)
2096
d->dateMonthNamePossessive = possessive;
2099
void KLocale::setTimeFormat(const QString & format)
2102
m_timeFormat = format.stripWhiteSpace();
2105
void KLocale::setWeekStartsMonday(bool start) //deprecated
2109
d->weekStartDay = 1;
2111
d->weekStartDay = 7;
2114
void KLocale::setWeekStartDay(int day)
2118
d->weekStartDay = 1; //Monday is default
2120
d->weekStartDay = day;
2123
QString KLocale::dateFormat() const
2126
return m_dateFormat;
2129
QString KLocale::dateFormatShort() const
2132
return m_dateFormatShort;
2135
QString KLocale::timeFormat() const
2138
return m_timeFormat;
2141
void KLocale::setDecimalSymbol(const QString & symbol)
2144
m_decimalSymbol = symbol.stripWhiteSpace();
2147
void KLocale::setThousandsSeparator(const QString & separator)
2150
// allow spaces here
2151
m_thousandsSeparator = separator;
2154
void KLocale::setPositiveSign(const QString & sign)
2157
m_positiveSign = sign.stripWhiteSpace();
2160
void KLocale::setNegativeSign(const QString & sign)
2163
m_negativeSign = sign.stripWhiteSpace();
2166
void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
2169
m_positiveMonetarySignPosition = signpos;
2172
void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
2175
m_negativeMonetarySignPosition = signpos;
2178
void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
2181
m_positivePrefixCurrencySymbol = prefix;
2184
void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
2187
m_negativePrefixCurrencySymbol = prefix;
2190
void KLocale::setFracDigits(int digits)
2193
m_fracDigits = digits;
2196
void KLocale::setMonetaryThousandsSeparator(const QString & separator)
2199
// allow spaces here
2200
m_monetaryThousandsSeparator = separator;
2203
void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
2206
m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
2209
void KLocale::setCurrencySymbol(const QString & symbol)
2212
m_currencySymbol = symbol.stripWhiteSpace();
2215
int KLocale::pageSize() const
2221
void KLocale::setPageSize(int pageSize)
2223
// #### check if it's in range??
2225
d->pageSize = pageSize;
2228
KLocale::MeasureSystem KLocale::measureSystem() const
2231
return d->measureSystem;
2234
void KLocale::setMeasureSystem(MeasureSystem value)
2237
d->measureSystem = value;
2240
QString KLocale::defaultLanguage()
2242
return QString::fromLatin1("en_US");
2245
QString KLocale::defaultCountry()
2247
return QString::fromLatin1("C");
2250
const char * KLocale::encoding() const
2253
if (0==qstrcmp("System", codecForEncoding()->name()))
2255
//win32 returns "System" codec name here but KDE apps expect a real name:
2256
strcpy(d->win32SystemEncoding, "cp ");
2257
if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT),
2258
LOCALE_IDEFAULTANSICODEPAGE, d->win32SystemEncoding+3, sizeof(d->win32SystemEncoding)-3-1 ))
2260
return d->win32SystemEncoding;
2264
return codecForEncoding()->name();
2267
int KLocale::encodingMib() const
2269
return codecForEncoding()->mibEnum();
2272
int KLocale::fileEncodingMib() const
2274
if (d->utf8FileEncoding)
2276
return codecForEncoding()->mibEnum();
2279
QTextCodec * KLocale::codecForEncoding() const
2281
return d->codecForEncoding;
2284
bool KLocale::setEncoding(int mibEnum)
2286
QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
2288
d->codecForEncoding = codec;
2293
QStringList KLocale::languagesTwoAlpha() const
2295
if (d->langTwoAlpha.count())
2296
return d->langTwoAlpha;
2298
const QStringList &origList = languageList();
2302
KConfig config(QString::fromLatin1("language.codes"), true, false);
2303
config.setGroup("TwoLetterCodes");
2305
for ( QStringList::ConstIterator it = origList.begin();
2306
it != origList.end();
2310
QStringList langLst;
2311
if (config.hasKey( lang ))
2312
langLst = config.readListEntry( lang );
2315
int i = lang.find('_');
2321
for ( QStringList::ConstIterator langIt = langLst.begin();
2322
langIt != langLst.end();
2325
if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
2329
d->langTwoAlpha = result;
2333
QStringList KLocale::allLanguagesTwoAlpha() const
2336
d->languages = new KConfig("all_languages", true, false, "locale");
2338
return d->languages->groupList();
2341
QString KLocale::twoAlphaToLanguageName(const QString &code) const
2344
d->languages = new KConfig("all_languages", true, false, "locale");
2346
QString groupName = code;
2347
const int i = groupName.find('_');
2348
groupName.replace(0, i, groupName.left(i).lower());
2350
d->languages->setGroup(groupName);
2351
return d->languages->readEntry("Name");
2354
QStringList KLocale::allCountriesTwoAlpha() const
2356
QStringList countries;
2357
QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
2358
for(QStringList::ConstIterator it = paths.begin();
2359
it != paths.end(); ++it)
2361
QString code = (*it).mid((*it).length()-16, 2);
2363
countries.append(code);
2368
QString KLocale::twoAlphaToCountryName(const QString &code) const
2370
KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
2371
cfg.setGroup("KCM Locale");
2372
return cfg.readEntry("Name");
2375
void KLocale::setCalendar(const QString & calType)
2379
d->calendarType = calType;
2385
QString KLocale::calendarType() const
2389
return d->calendarType;
2392
const KCalendarSystem * KLocale::calendar() const
2396
// Check if it's the correct calendar?!?
2398
d->calendar = KCalendarSystemFactory::create( d->calendarType, this );
2403
KLocale::KLocale(const KLocale & rhs)
2405
d = new KLocalePrivate;
2410
KLocale & KLocale::operator=(const KLocale & rhs)
2412
// Numbers and money
2413
m_decimalSymbol = rhs.m_decimalSymbol;
2414
m_thousandsSeparator = rhs.m_thousandsSeparator;
2415
m_currencySymbol = rhs.m_currencySymbol;
2416
m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
2417
m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
2418
m_positiveSign = rhs.m_positiveSign;
2419
m_negativeSign = rhs.m_negativeSign;
2420
m_fracDigits = rhs.m_fracDigits;
2421
m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
2422
m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
2423
m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
2424
m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
2427
m_timeFormat = rhs.m_timeFormat;
2428
m_dateFormat = rhs.m_dateFormat;
2429
m_dateFormatShort = rhs.m_dateFormatShort;
2431
m_language = rhs.m_language;
2432
m_country = rhs.m_country;
2434
// the assignment operator works here
2436
d->languages = 0; // Don't copy languages
2437
d->calendar = 0; // Don't copy the calendar
2442
bool KLocale::setCharset(const QString & ) { return true; }
2443
QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); }
2447
void nothing() { i18n("&Next"); }