• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

KDECore

klocalizedstring.cpp
Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002     Copyright (C) 2006 Chusslove Illich <caslav.ilic@gmx.net>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <klocalizedstring.h>
00021 
00022 #include <config.h>
00023 
00024 #include <kglobal.h>
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027 #include <klocale_p.h>
00028 #include <klibrary.h>
00029 #include <kstandarddirs.h>
00030 #include <ktranscript_p.h>
00031 #include <kuitsemantics_p.h>
00032 #include "kcatalogname_p.h"
00033 
00034 #include <QMutexLocker>
00035 #include <QStringList>
00036 #include <QByteArray>
00037 #include <QChar>
00038 #include <QHash>
00039 #include <QList>
00040 #include <QVector>
00041 
00042 // Truncates string, for output of long messages.
00043 static QString shortenMessage (const QString &str)
00044 {
00045     const int maxlen = 20;
00046     if (str.length() <= maxlen)
00047         return str;
00048     else
00049         return str.left(maxlen).append(QLatin1String("..."));
00050 }
00051 
00052 typedef qulonglong pluraln;
00053 typedef qlonglong intn;
00054 typedef qulonglong uintn;
00055 typedef double realn;
00056 
00057 class KLocalizedStringPrivateStatics;
00058 
00059 class KLocalizedStringPrivate
00060 {
00061     friend class KLocalizedString;
00062 
00063     QStringList args;
00064     QList<QVariant> vals;
00065     bool numberSet;
00066     pluraln number;
00067     int numberOrd;
00068     QByteArray ctxt;
00069     QHash<QString, QString> dynctxt;
00070     QByteArray msg;
00071     QByteArray plural;
00072 
00073     QString toString (const KLocale *locale, const QString *catalogName) const;
00074     QString selectForEnglish () const;
00075     QString substituteSimple (const QString &trans,
00076                               const QChar &plchar = QLatin1Char('%'),
00077                               bool partial = false) const;
00078     QString postFormat (const QString &text,
00079                         const QString &lang,
00080                         const QString &ctxt) const;
00081     QString substituteTranscript (const QString &trans,
00082                                   const QString &lang,
00083                                   const QString &ctry,
00084                                   const QString &final,
00085                                   bool &fallback) const;
00086     int resolveInterpolation (const QString &trans, int pos,
00087                               const QString &lang,
00088                               const QString &ctry,
00089                               const QString &final,
00090                               QString &result,
00091                               bool &fallback) const;
00092     QVariant segmentToValue (const QString &arg) const;
00093     QString postTranscript (const QString &pcall,
00094                             const QString &lang,
00095                             const QString &ctry,
00096                             const QString &final) const;
00097 
00098     static void notifyCatalogsUpdated (const QStringList &languages,
00099                                        const QList<KCatalogName> &catalogs);
00100     static void loadTranscript ();
00101 };
00102 
00103 class KLocalizedStringPrivateStatics
00104 {
00105     public:
00106 
00107     const QString theFence;
00108     const QString startInterp;
00109     const QString endInterp;
00110     const QChar scriptPlchar;
00111     const QChar scriptVachar;
00112 
00113     const QString scriptDir;
00114     QHash<QString, QStringList> scriptModules;
00115     QList<QStringList> scriptModulesToLoad;
00116 
00117     bool loadTranscriptCalled;
00118     KTranscript *ktrs;
00119 
00120     QHash<QString, KuitSemantics*> formatters;
00121 
00122     KLocalizedStringPrivateStatics () :
00123         theFence(QLatin1String("|/|")),
00124         startInterp(QLatin1String("$[")),
00125         endInterp(QLatin1String("]")),
00126         scriptPlchar(QLatin1Char('%')),
00127         scriptVachar(QLatin1Char('^')),
00128 
00129         scriptDir(QLatin1String("LC_SCRIPTS")),
00130         scriptModules(),
00131         scriptModulesToLoad(),
00132 
00133         loadTranscriptCalled(false),
00134         ktrs(NULL),
00135 
00136         formatters()
00137     {}
00138 
00139     ~KLocalizedStringPrivateStatics ()
00140     {
00141         // ktrs is handled by KLibLoader.
00142         //delete ktrs;
00143         qDeleteAll(formatters);
00144     }
00145 };
00146 K_GLOBAL_STATIC(KLocalizedStringPrivateStatics, staticsKLSP)
00147 
00148 KLocalizedString::KLocalizedString ()
00149 : d(new KLocalizedStringPrivate)
00150 {
00151     d->numberSet = false;
00152     d->number = 0;
00153     d->numberOrd = 0;
00154 }
00155 
00156 KLocalizedString::KLocalizedString (const char *ctxt,
00157                                     const char *msg, const char *plural)
00158 : d(new KLocalizedStringPrivate)
00159 {
00160     d->ctxt = ctxt;
00161     d->msg = msg;
00162     d->plural = plural;
00163     d->numberSet = false;
00164     d->number = 0;
00165     d->numberOrd = 0;
00166 }
00167 
00168 KLocalizedString::KLocalizedString(const KLocalizedString &rhs)
00169 : d(new KLocalizedStringPrivate(*rhs.d))
00170 {
00171 }
00172 
00173 KLocalizedString& KLocalizedString::operator= (const KLocalizedString &rhs)
00174 {
00175     if (&rhs != this)
00176     {
00177         *d = *rhs.d;
00178     }
00179     return *this;
00180 }
00181 
00182 KLocalizedString::~KLocalizedString ()
00183 {
00184     delete d;
00185 }
00186 
00187 bool KLocalizedString::isEmpty () const
00188 {
00189     return d->msg.isEmpty();
00190 }
00191 
00192 QString KLocalizedString::toString () const
00193 {
00194     return d->toString(KGlobal::locale(), NULL);
00195 }
00196 
00197 QString KLocalizedString::toString (const QString &catalogName) const
00198 {
00199     return d->toString(KGlobal::locale(), &catalogName);
00200 }
00201 
00202 QString KLocalizedString::toString (const KLocale *locale) const
00203 {
00204     return d->toString(locale, NULL);
00205 }
00206 
00207 QString KLocalizedString::toString (const KLocale *locale,
00208                                     const QString &catalogName) const
00209 {
00210     return d->toString(locale, &catalogName);
00211 }
00212 
00213 QString KLocalizedStringPrivate::toString (const KLocale *locale,
00214                                            const QString *catalogName) const
00215 {
00216     const KLocalizedStringPrivateStatics *s = staticsKLSP;
00217 
00218     QMutexLocker lock(kLocaleMutex());
00219 
00220     // Assure the message has been supplied.
00221     if (msg.isEmpty())
00222     {
00223         kDebug(173) << "Trying to convert empty KLocalizedString to QString.";
00224         #ifndef NDEBUG
00225         return QString::fromLatin1("(I18N_EMPTY_MESSAGE)");
00226         #else
00227         return QString();
00228         #endif
00229     }
00230 
00231     // Check whether plural argument has been supplied, if message has plural.
00232     if (!plural.isEmpty() && !numberSet)
00233         kDebug(173) << QString::fromLatin1("Plural argument to message {%1} not supplied before conversion.")
00234                               .arg(shortenMessage(QString::fromUtf8(msg)));
00235 
00236     // Get raw translation.
00237     QString rawtrans, lang, ctry;
00238     QByteArray catname;
00239     if (catalogName != NULL) {
00240         catname = catalogName->toUtf8();
00241     }
00242     if (locale != NULL) {
00243         if (!ctxt.isEmpty() && !plural.isEmpty()) {
00244             locale->translateRawFrom(catname, ctxt, msg, plural, number,
00245                                      &lang, &rawtrans);
00246         } else if (!plural.isEmpty()) {
00247             locale->translateRawFrom(catname, msg, plural, number,
00248                                      &lang, &rawtrans);
00249         } else if (!ctxt.isEmpty()) {
00250             locale->translateRawFrom(catname, ctxt, msg,
00251                                      &lang, &rawtrans);
00252         } else {
00253             locale->translateRawFrom(catname, msg,
00254                                      &lang, &rawtrans);
00255         }
00256         ctry = locale->country();
00257     } else {
00258         lang = KLocale::defaultLanguage();
00259         ctry = QLatin1Char('C');
00260         rawtrans = selectForEnglish();
00261     }
00262 
00263     // Set ordinary translation and possibly scripted translation.
00264     QString trans, strans;
00265     int cdpos = rawtrans.indexOf(s->theFence);
00266     if (cdpos > 0)
00267     {
00268         // Script fence has been found, strip the scripted from the
00269         // ordinary translation.
00270         trans = rawtrans.left(cdpos);
00271 
00272         // Scripted translation.
00273         strans = rawtrans.mid(cdpos + s->theFence.length());
00274 
00275         // Try to initialize Transcript if not initialized, and script not empty.
00276         if (   !s->loadTranscriptCalled && !strans.isEmpty()
00277             && locale && locale->useTranscript())
00278         {
00279             if (KGlobal::hasMainComponent())
00280                 loadTranscript();
00281             else
00282                 kDebug(173) << QString::fromLatin1("Scripted message {%1} before transcript engine can be loaded.")
00283                                       .arg(shortenMessage(trans));
00284         }
00285     }
00286     else if (cdpos < 0)
00287     {
00288         // No script fence, use translation as is.
00289         trans = rawtrans;
00290     }
00291     else // cdpos == 0
00292     {
00293         // The msgstr starts with the script fence, no ordinary translation.
00294         // This is not allowed, consider message not translated.
00295         kDebug(173) << QString::fromLatin1("Scripted message {%1} without ordinary translation, discarded.")
00296                                .arg(shortenMessage(trans)) ;
00297         trans = selectForEnglish();
00298     }
00299 
00300     // Substitute placeholders in ordinary translation.
00301     QString final = substituteSimple(trans);
00302     // Post-format ordinary translation.
00303     final = postFormat(final, lang, QString::fromLatin1(ctxt));
00304 
00305     // If there is also a scripted translation.
00306     if (!strans.isEmpty()) {
00307         // Evaluate scripted translation.
00308         bool fallback;
00309         QString sfinal = substituteTranscript(strans, lang, ctry, final, fallback);
00310 
00311         // If any translation produced and no fallback requested.
00312         if (!sfinal.isEmpty() && !fallback) {
00313             final = postFormat(sfinal, lang, QString::fromLatin1(ctxt));
00314         }
00315     }
00316 
00317     // Execute any scripted post calls; they cannot modify the final result,
00318     // but are used to set states.
00319     if (s->ktrs != NULL)
00320     {
00321         QStringList pcalls = s->ktrs->postCalls(lang);
00322         foreach(const QString &pcall, pcalls)
00323             postTranscript(pcall, lang, ctry, final);
00324     }
00325 
00326     return final;
00327 }
00328 
00329 QString KLocalizedStringPrivate::selectForEnglish () const
00330 {
00331     QString trans;
00332 
00333     if (!plural.isEmpty()) {
00334         if (number == 1) {
00335             trans = QString::fromUtf8(msg);
00336         }
00337         else {
00338             trans = QString::fromUtf8(plural);
00339         }
00340     }
00341     else {
00342         trans = QString::fromUtf8(msg);
00343     }
00344 
00345     return trans;
00346 }
00347 
00348 QString KLocalizedStringPrivate::substituteSimple (const QString &trans,
00349                                                    const QChar &plchar,
00350                                                    bool partial) const
00351 {
00352     #ifdef NDEBUG
00353     Q_UNUSED(partial);
00354     #endif
00355 
00356     QStringList tsegs; // text segments per placeholder occurrence
00357     QList<int> plords; // ordinal numbers per placeholder occurrence
00358     #ifndef NDEBUG
00359     QVector<int> ords; // indicates which placeholders are present
00360     #endif
00361     int slen = trans.length();
00362     int spos = 0;
00363     int tpos = trans.indexOf(plchar);
00364     while (tpos >= 0)
00365     {
00366         int ctpos = tpos;
00367 
00368         tpos++;
00369         if (tpos == slen)
00370             break;
00371 
00372         if (trans[tpos].digitValue() > 0) // %0 not considered a placeholder
00373         {
00374             // Get the placeholder ordinal.
00375             int plord = 0;
00376             while (tpos < slen && trans[tpos].digitValue() >= 0)
00377             {
00378                 plord = 10 * plord + trans[tpos].digitValue();
00379                 tpos++;
00380             }
00381             plord--; // ordinals are zero based
00382 
00383             #ifndef NDEBUG
00384             // Perhaps enlarge storage for indicators.
00385             // Note that QVector<int> will initialize new elements to 0,
00386             // as they are supposed to be.
00387             if (plord >= ords.size())
00388                 ords.resize(plord + 1);
00389 
00390             // Indicate that placeholder with computed ordinal is present.
00391             ords[plord] = 1;
00392             #endif
00393 
00394             // Store text segment prior to placeholder and placeholder number.
00395             tsegs.append(trans.mid(spos, ctpos - spos));
00396             plords.append(plord);
00397 
00398             // Position of next text segment.
00399             spos = tpos;
00400         }
00401 
00402         tpos = trans.indexOf(plchar, tpos);
00403     }
00404     // Store last text segment.
00405     tsegs.append(trans.mid(spos));
00406 
00407     #ifndef NDEBUG
00408     // Perhaps enlarge storage for plural-number ordinal.
00409     if (!plural.isEmpty() && numberOrd >= ords.size())
00410         ords.resize(numberOrd + 1);
00411 
00412     // Message might have plural but without plural placeholder, which is an
00413     // allowed state. To ease further logic, indicate that plural placeholder
00414     // is present anyway if message has plural.
00415     if (!plural.isEmpty())
00416         ords[numberOrd] = 1;
00417     #endif
00418 
00419     // Assemble the final string from text segments and arguments.
00420     QString final;
00421     for (int i = 0; i < plords.size(); i++)
00422     {
00423         final.append(tsegs.at(i));
00424         if (plords.at(i) >= args.size())
00425         // too little arguments
00426         {
00427             // put back the placeholder
00428             final.append(QLatin1Char('%') + QString::number(plords.at(i) + 1));
00429             #ifndef NDEBUG
00430             if (!partial)
00431                 // spoof the message
00432                 final.append(QLatin1String("(I18N_ARGUMENT_MISSING)"));
00433             #endif
00434         }
00435         else
00436         // just fine
00437             final.append(args.at(plords.at(i)));
00438     }
00439     final.append(tsegs.last());
00440 
00441     #ifndef NDEBUG
00442     if (!partial)
00443     {
00444         // Check that there are no gaps in numbering sequence of placeholders.
00445         bool gaps = false;
00446         for (int i = 0; i < ords.size(); i++)
00447             if (!ords.at(i))
00448             {
00449                 gaps = true;
00450                 kDebug(173) << QString::fromLatin1("Placeholder %%1 skipped in message {%2}.")
00451                                       .arg(QString::number(i + 1), shortenMessage(trans));
00452             }
00453         // If no gaps, check for mismatch between number of unique placeholders and
00454         // actually supplied arguments.
00455         if (!gaps && ords.size() != args.size())
00456             kDebug(173) << QString::fromLatin1("%1 instead of %2 arguments to message {%3} supplied before conversion.")
00457                                   .arg(args.size()).arg(ords.size()).arg(shortenMessage(trans));
00458 
00459         // Some spoofs.
00460         if (gaps)
00461             final.append(QLatin1String("(I18N_GAPS_IN_PLACEHOLDER_SEQUENCE)"));
00462         if (ords.size() < args.size())
00463             final.append(QLatin1String("(I18N_EXCESS_ARGUMENTS_SUPPLIED)"));
00464         if (!plural.isEmpty() && !numberSet)
00465             final.append(QLatin1String("(I18N_PLURAL_ARGUMENT_MISSING)"));
00466     }
00467     #endif
00468 
00469     return final;
00470 }
00471 
00472 QString KLocalizedStringPrivate::postFormat (const QString &text,
00473                                              const QString &lang,
00474                                              const QString &ctxt) const
00475 {
00476     const KLocalizedStringPrivateStatics *s = staticsKLSP;
00477     QMutexLocker lock(kLocaleMutex());
00478 
00479     QString final = text;
00480 
00481     // Transform any semantic markup into visual formatting.
00482     if (s->formatters.contains(lang)) {
00483         final = s->formatters[lang]->format(final, ctxt);
00484     }
00485 
00486     return final;
00487 }
00488 
00489 QString KLocalizedStringPrivate::substituteTranscript (const QString &strans,
00490                                                        const QString &lang,
00491                                                        const QString &ctry,
00492                                                        const QString &final,
00493                                                        bool &fallback) const
00494 {
00495     const KLocalizedStringPrivateStatics *s = staticsKLSP;
00496     QMutexLocker lock(kLocaleMutex());
00497 
00498     if (s->ktrs == NULL)
00499         // Scripting engine not available.
00500         return QString();
00501 
00502     // Iterate by interpolations.
00503     QString sfinal;
00504     fallback = false;
00505     int ppos = 0;
00506     int tpos = strans.indexOf(s->startInterp);
00507     while (tpos >= 0)
00508     {
00509         // Resolve substitutions in preceding text.
00510         QString ptext = substituteSimple(strans.mid(ppos, tpos - ppos),
00511                                          s->scriptPlchar, true);
00512         sfinal.append(ptext);
00513 
00514         // Resolve interpolation.
00515         QString result;
00516         bool fallbackLocal;
00517         tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
00518                                     result, fallbackLocal);
00519 
00520         // If there was a problem in parsing the interpolation, cannot proceed
00521         // (debug info already reported while parsing).
00522         if (tpos < 0) {
00523             return QString();
00524         }
00525         // If fallback has been explicitly requested, indicate global fallback
00526         // but proceed with evaluations (other interpolations may set states).
00527         if (fallbackLocal) {
00528             fallback = true;
00529         }
00530 
00531         // Add evaluated interpolation to the text.
00532         sfinal.append(result);
00533 
00534         // On to next interpolation.
00535         ppos = tpos;
00536         tpos = strans.indexOf(s->startInterp, tpos);
00537     }
00538     // Last text segment.
00539     sfinal.append(substituteSimple(strans.mid(ppos), s->scriptPlchar, true));
00540 
00541     // Return empty string if fallback was requested.
00542     return fallback ? QString() : sfinal;
00543 }
00544 
00545 int KLocalizedStringPrivate::resolveInterpolation (const QString &strans,
00546                                                    int pos,
00547                                                    const QString &lang,
00548                                                    const QString &ctry,
00549                                                    const QString &final,
00550                                                    QString &result,
00551                                                    bool &fallback) const
00552 {
00553     // pos is the position of opening character sequence.
00554     // Returns the position of first character after closing sequence,
00555     // or -1 in case of parsing error.
00556     // result is set to result of Transcript evaluation.
00557     // fallback is set to true if Transcript evaluation requested so.
00558 
00559     KLocalizedStringPrivateStatics *s = staticsKLSP;
00560     QMutexLocker lock(kLocaleMutex());
00561 
00562     result.clear();
00563     fallback = false;
00564 
00565     // Split interpolation into arguments.
00566     QList<QVariant> iargs;
00567     int slen = strans.length();
00568     int islen = s->startInterp.length();
00569     int ielen = s->endInterp.length();
00570     int tpos = pos + s->startInterp.length();
00571     while (1)
00572     {
00573         // Skip whitespace.
00574         while (tpos < slen && strans[tpos].isSpace()) {
00575             ++tpos;
00576         }
00577         if (tpos == slen) {
00578             kDebug(173) << QString::fromLatin1("Unclosed interpolation {%1} in message {%2}.")
00579                                   .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
00580             return -1;
00581         }
00582         if (strans.mid(tpos, ielen) == s->endInterp) {
00583             break; // no more arguments
00584         }
00585 
00586         // Parse argument: may be concatenated from free and quoted text,
00587         // and sub-interpolations.
00588         // Free and quoted segments may contain placeholders, substitute them;
00589         // recurse into sub-interpolations.
00590         // Free segments may be value references, parse and record for
00591         // consideration at the end.
00592         // Mind backslash escapes throughout.
00593         QStringList segs;
00594         QVariant vref;
00595         while (   !strans[tpos].isSpace()
00596                && strans.mid(tpos, ielen) != s->endInterp)
00597         {
00598             if (strans[tpos] == QLatin1Char('\'')) { // quoted segment
00599                 QString seg;
00600                 ++tpos; // skip opening quote
00601                 // Find closing quote.
00602                 while (tpos < slen && strans[tpos] != QLatin1Char('\'')) {
00603                     if (strans[tpos] == QLatin1Char('\\'))
00604                         ++tpos; // escape next character
00605                     seg.append(strans[tpos]);
00606                     ++tpos;
00607                 }
00608                 if (tpos == slen) {
00609                     kDebug(173) << QString::fromLatin1("Unclosed quote in interpolation {%1} in message {%2}.")
00610                                         .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
00611                     return -1;
00612                 }
00613 
00614                 // Append to list of segments, resolving placeholders.
00615                 segs.append(substituteSimple(seg, s->scriptPlchar, true));
00616 
00617                 ++tpos; // skip closing quote
00618             }
00619             else if (strans.mid(tpos, islen) == s->startInterp) { // sub-interpolation
00620                 QString resultLocal;
00621                 bool fallbackLocal;
00622                 tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
00623                                             resultLocal, fallbackLocal);
00624                 if (tpos < 0) { // unrecoverable problem in sub-interpolation
00625                     // Error reported in the subcall.
00626                     return tpos;
00627                 }
00628                 if (fallbackLocal) { // sub-interpolation requested fallback
00629                     fallback = true;
00630                 }
00631                 segs.append(resultLocal);
00632             }
00633             else { // free segment
00634                 QString seg;
00635                 // Find whitespace, quote, opening or closing sequence.
00636                 while (   tpos < slen
00637                        && !strans[tpos].isSpace() && strans[tpos] != QLatin1Char('\'')
00638                        && strans.mid(tpos, islen) != s->startInterp
00639                        && strans.mid(tpos, ielen) != s->endInterp)
00640                 {
00641                     if (strans[tpos] == QLatin1Char('\\'))
00642                         ++tpos; // escape next character
00643                     seg.append(strans[tpos]);
00644                     ++tpos;
00645                 }
00646                 if (tpos == slen) {
00647                     kDebug(173) << QString::fromLatin1("Non-terminated interpolation {%1} in message {%2}.")
00648                                         .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
00649                     return -1;
00650                 }
00651 
00652                 // The free segment may look like a value reference;
00653                 // in that case, record which value it would reference,
00654                 // and add verbatim to the segment list.
00655                 // Otherwise, do a normal substitution on the segment.
00656                 vref = segmentToValue(seg);
00657                 if (vref.isValid()) {
00658                     segs.append(seg);
00659                 }
00660                 else {
00661                     segs.append(substituteSimple(seg, s->scriptPlchar, true));
00662                 }
00663             }
00664         }
00665 
00666         // Append this argument to rest of the arguments.
00667         // If the there was a single text segment and it was a proper value
00668         // reference, add it instead of the joined segments.
00669         // Otherwise, add the joined segments.
00670         if (segs.size() == 1 && vref.isValid()) {
00671             iargs.append(vref);
00672         }
00673         else {
00674             iargs.append(segs.join(QString()));
00675         }
00676     }
00677     tpos += ielen; // skip to first character after closing sequence
00678 
00679     // NOTE: Why not substitute placeholders (via substituteSimple) in one
00680     // global pass, then handle interpolations in second pass? Because then
00681     // there is the danger of substituted text or sub-interpolations producing
00682     // quotes and escapes themselves, which would mess up the parsing.
00683 
00684     // Evaluate interpolation.
00685     QString msgctxt = QString::fromUtf8(ctxt);
00686     QString msgid = QString::fromUtf8(msg);
00687     QString scriptError;
00688     bool fallbackLocal;
00689     result = s->ktrs->eval(iargs, lang, ctry,
00690                            msgctxt, dynctxt, msgid,
00691                            args, vals, final, s->scriptModulesToLoad,
00692                            scriptError, fallbackLocal);
00693     // s->scriptModulesToLoad will be cleared during the call.
00694 
00695     if (fallbackLocal) { // evaluation requested fallback
00696         fallback = true;
00697     }
00698     if (!scriptError.isEmpty()) { // problem with evaluation
00699         fallback = true; // also signal fallback
00700         if (!scriptError.isEmpty()) {
00701             kDebug(173) << QString::fromLatin1("Interpolation {%1} in {%2} failed: %3")
00702                                   .arg(strans.mid(pos, tpos - pos), shortenMessage(strans), scriptError);
00703         }
00704     }
00705 
00706     return tpos;
00707 }
00708 
00709 QVariant KLocalizedStringPrivate::segmentToValue (const QString &seg) const
00710 {
00711     const KLocalizedStringPrivateStatics *s = staticsKLSP;
00712     QMutexLocker lock(kLocaleMutex());
00713 
00714     // Return invalid variant if segment is either not a proper
00715     // value reference, or the reference is out of bounds.
00716 
00717     // Value reference must start with a special character.
00718     if (seg.left(1) != s->scriptVachar) {
00719         return QVariant();
00720     }
00721 
00722     // Reference number must start with 1-9.
00723     // (If numstr is empty, toInt() will return 0.)
00724     QString numstr = seg.mid(1);
00725     if (numstr.left(1).toInt() < 1) {
00726         return QVariant();
00727     }
00728 
00729     // Number must be valid and in bounds.
00730     bool ok;
00731     int index = numstr.toInt(&ok) - 1;
00732     if (!ok || index >= vals.size()) {
00733         return QVariant();
00734     }
00735 
00736     // Passed all hoops.
00737     return vals.at(index);
00738 }
00739 
00740 QString KLocalizedStringPrivate::postTranscript (const QString &pcall,
00741                                                  const QString &lang,
00742                                                  const QString &ctry,
00743                                                  const QString &final) const
00744 {
00745     KLocalizedStringPrivateStatics *s = staticsKLSP;
00746     QMutexLocker lock(kLocaleMutex());
00747 
00748     if (s->ktrs == NULL)
00749         // Scripting engine not available.
00750         // (Though this cannot happen, we wouldn't be here then.)
00751         return QString();
00752 
00753     // Resolve the post call.
00754     QList<QVariant> iargs;
00755     iargs.append(pcall);
00756     QString msgctxt = QString::fromUtf8(ctxt);
00757     QString msgid = QString::fromUtf8(msg);
00758     QString scriptError;
00759     bool fallback;
00760     QString dummy = s->ktrs->eval(iargs, lang, ctry,
00761                                   msgctxt, dynctxt, msgid,
00762                                   args, vals, final, s->scriptModulesToLoad,
00763                                   scriptError, fallback);
00764     // s->scriptModulesToLoad will be cleared during the call.
00765 
00766     // If the evaluation went wrong.
00767     if (!scriptError.isEmpty())
00768     {
00769         kDebug(173) << QString::fromLatin1("Post call {%1} for message {%2} failed: %3")
00770                               .arg(pcall, shortenMessage(msgid), scriptError);
00771         return QString();
00772     }
00773 
00774     return final;
00775 }
00776 
00777 static QString wrapNum (const QString &tag, const QString &numstr,
00778                         int fieldWidth, const QChar &fillChar)
00779 {
00780     QString optag;
00781     if (fieldWidth != 0) {
00782         QString fillString = KuitSemantics::escape(fillChar);
00783         optag = QString::fromLatin1("<%1 width='%2' fill='%3'>")
00784                        .arg(tag, QString::number(fieldWidth), fillString);
00785     } else {
00786         optag = QString::fromLatin1("<%1>").arg(tag);
00787     }
00788     QString cltag = QString::fromLatin1("</%1>").arg(tag);
00789     return optag + numstr + cltag;
00790 }
00791 
00792 KLocalizedString KLocalizedString::subs (int a, int fieldWidth, int base,
00793                                          const QChar &fillChar) const
00794 {
00795     KLocalizedString kls(*this);
00796     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00797         kls.d->number = static_cast<pluraln>(abs(a));
00798         kls.d->numberSet = true;
00799         kls.d->numberOrd = d->args.size();
00800     }
00801     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
00802                                fieldWidth, fillChar));
00803     kls.d->vals.append(static_cast<intn>(a));
00804     return kls;
00805 }
00806 
00807 KLocalizedString KLocalizedString::subs (uint a, int fieldWidth, int base,
00808                                          const QChar &fillChar) const
00809 {
00810     KLocalizedString kls(*this);
00811     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00812         kls.d->number = static_cast<pluraln>(a);
00813         kls.d->numberSet = true;
00814         kls.d->numberOrd = d->args.size();
00815     }
00816     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
00817                                fieldWidth, fillChar));
00818     kls.d->vals.append(static_cast<uintn>(a));
00819     return kls;
00820 }
00821 
00822 KLocalizedString KLocalizedString::subs (long a, int fieldWidth, int base,
00823                                          const QChar &fillChar) const
00824 {
00825     KLocalizedString kls(*this);
00826     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00827         kls.d->number = static_cast<pluraln>(abs(a));
00828         kls.d->numberSet = true;
00829         kls.d->numberOrd = d->args.size();
00830     }
00831     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
00832                                fieldWidth, fillChar));
00833     kls.d->vals.append(static_cast<intn>(a));
00834     return kls;
00835 }
00836 
00837 KLocalizedString KLocalizedString::subs (ulong a, int fieldWidth, int base,
00838                                          const QChar &fillChar) const
00839 {
00840     KLocalizedString kls(*this);
00841     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00842         kls.d->number = static_cast<pluraln>(a);
00843         kls.d->numberSet = true;
00844         kls.d->numberOrd = d->args.size();
00845     }
00846     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
00847                                fieldWidth, fillChar));
00848     kls.d->vals.append(static_cast<uintn>(a));
00849     return kls;
00850 }
00851 
00852 KLocalizedString KLocalizedString::subs (qlonglong a, int fieldWidth, int base,
00853                                          const QChar &fillChar) const
00854 {
00855     KLocalizedString kls(*this);
00856     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00857         kls.d->number = static_cast<pluraln>(qAbs(a));
00858         kls.d->numberSet = true;
00859         kls.d->numberOrd = d->args.size();
00860     }
00861     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
00862                                fieldWidth, fillChar));
00863     kls.d->vals.append(static_cast<intn>(a));
00864     return kls;
00865 }
00866 
00867 KLocalizedString KLocalizedString::subs (qulonglong a, int fieldWidth, int base,
00868                                          const QChar &fillChar) const
00869 {
00870     KLocalizedString kls(*this);
00871     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00872         kls.d->number = static_cast<pluraln>(a);
00873         kls.d->numberSet = true;
00874         kls.d->numberOrd = d->args.size();
00875     }
00876     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
00877                                fieldWidth, fillChar));
00878     kls.d->vals.append(static_cast<uintn>(a));
00879     return kls;
00880 }
00881 
00882 KLocalizedString KLocalizedString::subs (double a, int fieldWidth,
00883                                          char format, int precision,
00884                                          const QChar &fillChar) const
00885 {
00886     KLocalizedString kls(*this);
00887     kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMREAL),
00888                                QString::number(a, format, precision),
00889                                fieldWidth, fillChar));
00890     kls.d->vals.append(static_cast<realn>(a));
00891     return kls;
00892 }
00893 
00894 KLocalizedString KLocalizedString::subs (QChar a, int fieldWidth,
00895                                          const QChar &fillChar) const
00896 {
00897     KLocalizedString kls(*this);
00898     kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
00899     kls.d->vals.append(QString(a));
00900     return kls;
00901 }
00902 
00903 KLocalizedString KLocalizedString::subs (const QString &a, int fieldWidth,
00904                                          const QChar &fillChar) const
00905 {
00906     KLocalizedString kls(*this);
00907     // if (!KuitSemantics::mightBeRichText(a)) { ...
00908     // Do not try to auto-escape non-rich-text alike arguments;
00909     // breaks compatibility with 4.0. Perhaps for KDE 5?
00910     // Perhaps bad idea alltogether (too much surprise)?
00911     kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
00912     kls.d->vals.append(a);
00913     return kls;
00914 }
00915 
00916 KLocalizedString KLocalizedString::inContext (const QString &key,
00917                                               const QString &text) const
00918 {
00919     KLocalizedString kls(*this);
00920     kls.d->dynctxt[key] = text;
00921     return kls;
00922 }
00923 
00924 KLocalizedString ki18n (const char* msg)
00925 {
00926     return KLocalizedString(NULL, msg, NULL);
00927 }
00928 
00929 KLocalizedString ki18nc (const char* ctxt, const char *msg)
00930 {
00931     return KLocalizedString(ctxt, msg, NULL);
00932 }
00933 
00934 KLocalizedString ki18np (const char* singular, const char* plural)
00935 {
00936     return KLocalizedString(NULL, singular, plural);
00937 }
00938 
00939 KLocalizedString ki18ncp (const char* ctxt,
00940                           const char* singular, const char* plural)
00941 {
00942     return KLocalizedString(ctxt, singular, plural);
00943 }
00944 
00945 extern "C"
00946 {
00947     typedef KTranscript *(*InitFunc)();
00948 }
00949 
00950 void KLocalizedStringPrivate::loadTranscript ()
00951 {
00952     KLocalizedStringPrivateStatics *s = staticsKLSP;
00953     QMutexLocker lock(kLocaleMutex());
00954 
00955     s->loadTranscriptCalled = true;
00956     s->ktrs = NULL; // null indicates that Transcript is not available
00957 
00958     KLibrary lib(QLatin1String("ktranscript"));
00959     if (!lib.load()) {
00960         kDebug(173) << "Cannot load transcript plugin:" << lib.errorString();
00961         return;
00962     }
00963 
00964     InitFunc initf = (InitFunc) lib.resolveFunction("load_transcript");
00965     if (!initf) {
00966         lib.unload();
00967         kDebug(173) << "Cannot find function load_transcript in transcript plugin.";
00968         return;
00969     }
00970 
00971     s->ktrs = initf();
00972 }
00973 
00974 void KLocalizedString::notifyCatalogsUpdated (const QStringList &languages,
00975                                               const QList<KCatalogName> &catalogs)
00976 {
00977     KLocalizedStringPrivate::notifyCatalogsUpdated(languages, catalogs);
00978 }
00979 
00980 void KLocalizedStringPrivate::notifyCatalogsUpdated (const QStringList &languages,
00981                                                      const QList<KCatalogName> &catalogs)
00982 {
00983     if (staticsKLSP.isDestroyed()) {
00984         return;
00985     }
00986     KLocalizedStringPrivateStatics *s = staticsKLSP;
00987     // Very important: do not the mutex here.
00988     //QMutexLocker lock(kLocaleMutex());
00989 
00990     // Find script modules for all included language/catalogs that have them,
00991     // and remember their paths.
00992     // A more specific module may reference the calls from a less specific,
00993     // and the catalog list is ordered from more to less specific. Therefore,
00994     // work on reversed list of catalogs.
00995     foreach (const QString &lang, languages) {
00996         for (int i = catalogs.size() - 1; i >= 0; --i) {
00997             const KCatalogName &cat(catalogs[i]);
00998 
00999             // Assemble module's relative path.
01000             QString modrpath =   lang + QLatin1Char('/') + s->scriptDir + QLatin1Char('/')
01001                             + cat.name + QLatin1Char('/') + cat.name + QLatin1String(".js");
01002 
01003             // Try to find this module.
01004             QString modapath = KStandardDirs::locate("locale", modrpath);
01005 
01006             // If the module exists and hasn't been already included.
01007             if (   !modapath.isEmpty()
01008                 && !s->scriptModules[lang].contains(cat.name))
01009             {
01010                 // Indicate that the module has been considered.
01011                 s->scriptModules[lang].append(cat.name);
01012 
01013                 // Store the absolute path and language of the module,
01014                 // to load on next script evaluation.
01015                 QStringList mod;
01016                 mod.append(modapath);
01017                 mod.append(lang);
01018                 s->scriptModulesToLoad.append(mod);
01019             }
01020         }
01021     }
01022 
01023     // Create visual formatters for each new language.
01024     foreach (const QString &lang, languages) {
01025         if (!s->formatters.contains(lang)) {
01026             s->formatters.insert(lang, new KuitSemantics(lang));
01027         }
01028     }
01029 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:28:11 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal