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

KDECore

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal