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

KDECore

  • kdecore
  • localization
klocalizedstring.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (C) 2006 Chusslove Illich <caslav.ilic@gmx.net>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include <klocalizedstring.h>
21
22#include <config.h>
23
24#include <kglobal.h>
25#include <kdebug.h>
26#include <klocale.h>
27#include <klocale_p.h>
28#include <klibrary.h>
29#include <kstandarddirs.h>
30#include <ktranscript_p.h>
31#include <kuitsemantics_p.h>
32#include "kcatalogname_p.h"
33
34#include <QMutexLocker>
35#include <QStringList>
36#include <QByteArray>
37#include <QChar>
38#include <QHash>
39#include <QList>
40#include <QVector>
41
42// Truncates string, for output of long messages.
43static QString shortenMessage (const QString &str)
44{
45 const int maxlen = 20;
46 if (str.length() <= maxlen)
47 return str;
48 else
49 return str.left(maxlen).append(QLatin1String("..."));
50}
51
52typedef qulonglong pluraln;
53typedef qlonglong intn;
54typedef qulonglong uintn;
55typedef double realn;
56
57class KLocalizedStringPrivateStatics;
58
59class KLocalizedStringPrivate
60{
61 friend class KLocalizedString;
62
63 QStringList args;
64 QList<QVariant> vals;
65 bool numberSet;
66 pluraln number;
67 int numberOrd;
68 QByteArray ctxt;
69 QHash<QString, QString> dynctxt;
70 QByteArray msg;
71 QByteArray plural;
72
73 QString toString (const KLocale *locale, const QString *catalogName) const;
74 QString selectForEnglish () const;
75 QString substituteSimple (const QString &trans,
76 const QChar &plchar = QLatin1Char('%'),
77 bool partial = false) const;
78 QString postFormat (const QString &text,
79 const QString &lang,
80 const QString &ctxt) const;
81 QString substituteTranscript (const QString &trans,
82 const QString &lang,
83 const QString &ctry,
84 const QString &final,
85 bool &fallback) const;
86 int resolveInterpolation (const QString &trans, int pos,
87 const QString &lang,
88 const QString &ctry,
89 const QString &final,
90 QString &result,
91 bool &fallback) const;
92 QVariant segmentToValue (const QString &arg) const;
93 QString postTranscript (const QString &pcall,
94 const QString &lang,
95 const QString &ctry,
96 const QString &final) const;
97
98 static void notifyCatalogsUpdated (const QStringList &languages,
99 const QList<KCatalogName> &catalogs);
100 static void loadTranscript ();
101};
102
103class KLocalizedStringPrivateStatics
104{
105 public:
106
107 const QString theFence;
108 const QString startInterp;
109 const QString endInterp;
110 const QChar scriptPlchar;
111 const QChar scriptVachar;
112
113 const QString scriptDir;
114 QHash<QString, QStringList> scriptModules;
115 QList<QStringList> scriptModulesToLoad;
116
117 bool loadTranscriptCalled;
118 KTranscript *ktrs;
119
120 QHash<QString, KuitSemantics*> formatters;
121
122 KLocalizedStringPrivateStatics () :
123 theFence(QLatin1String("|/|")),
124 startInterp(QLatin1String("$[")),
125 endInterp(QLatin1String("]")),
126 scriptPlchar(QLatin1Char('%')),
127 scriptVachar(QLatin1Char('^')),
128
129 scriptDir(QLatin1String("LC_SCRIPTS")),
130 scriptModules(),
131 scriptModulesToLoad(),
132
133 loadTranscriptCalled(false),
134 ktrs(NULL),
135
136 formatters()
137 {}
138
139 ~KLocalizedStringPrivateStatics ()
140 {
141 // ktrs is handled by KLibLoader.
142 //delete ktrs;
143 qDeleteAll(formatters);
144 }
145};
146K_GLOBAL_STATIC(KLocalizedStringPrivateStatics, staticsKLSP)
147
148KLocalizedString::KLocalizedString ()
149: d(new KLocalizedStringPrivate)
150{
151 d->numberSet = false;
152 d->number = 0;
153 d->numberOrd = 0;
154}
155
156KLocalizedString::KLocalizedString (const char *ctxt,
157 const char *msg, const char *plural)
158: d(new KLocalizedStringPrivate)
159{
160 d->ctxt = ctxt;
161 d->msg = msg;
162 d->plural = plural;
163 d->numberSet = false;
164 d->number = 0;
165 d->numberOrd = 0;
166}
167
168KLocalizedString::KLocalizedString(const KLocalizedString &rhs)
169: d(new KLocalizedStringPrivate(*rhs.d))
170{
171}
172
173KLocalizedString& KLocalizedString::operator= (const KLocalizedString &rhs)
174{
175 if (&rhs != this)
176 {
177 *d = *rhs.d;
178 }
179 return *this;
180}
181
182KLocalizedString::~KLocalizedString ()
183{
184 delete d;
185}
186
187bool KLocalizedString::isEmpty () const
188{
189 return d->msg.isEmpty();
190}
191
192QString KLocalizedString::toString () const
193{
194 return d->toString(KGlobal::locale(), NULL);
195}
196
197QString KLocalizedString::toString (const QString &catalogName) const
198{
199 return d->toString(KGlobal::locale(), &catalogName);
200}
201
202QString KLocalizedString::toString (const KLocale *locale) const
203{
204 return d->toString(locale, NULL);
205}
206
207QString KLocalizedString::toString (const KLocale *locale,
208 const QString &catalogName) const
209{
210 return d->toString(locale, &catalogName);
211}
212
213QString KLocalizedStringPrivate::toString (const KLocale *locale,
214 const QString *catalogName) const
215{
216 const KLocalizedStringPrivateStatics *s = staticsKLSP;
217
218 QMutexLocker lock(kLocaleMutex());
219
220 // Assure the message has been supplied.
221 if (msg.isEmpty())
222 {
223 kDebug(173) << "Trying to convert empty KLocalizedString to QString.";
224 #ifndef NDEBUG
225 return QString::fromLatin1("(I18N_EMPTY_MESSAGE)");
226 #else
227 return QString();
228 #endif
229 }
230
231 // Check whether plural argument has been supplied, if message has plural.
232 if (!plural.isEmpty() && !numberSet)
233 kDebug(173) << QString::fromLatin1("Plural argument to message {%1} not supplied before conversion.")
234 .arg(shortenMessage(QString::fromUtf8(msg)));
235
236 // Get raw translation.
237 QString rawtrans, lang, ctry;
238 QByteArray catname;
239 if (catalogName != NULL) {
240 catname = catalogName->toUtf8();
241 }
242 if (locale != NULL) {
243 if (!ctxt.isEmpty() && !plural.isEmpty()) {
244 locale->translateRawFrom(catname, ctxt, msg, plural, number,
245 &lang, &rawtrans);
246 } else if (!plural.isEmpty()) {
247 locale->translateRawFrom(catname, msg, plural, number,
248 &lang, &rawtrans);
249 } else if (!ctxt.isEmpty()) {
250 locale->translateRawFrom(catname, ctxt, msg,
251 &lang, &rawtrans);
252 } else {
253 locale->translateRawFrom(catname, msg,
254 &lang, &rawtrans);
255 }
256 ctry = locale->country();
257 } else {
258 lang = KLocale::defaultLanguage();
259 ctry = QLatin1Char('C');
260 rawtrans = selectForEnglish();
261 }
262
263 // Set ordinary translation and possibly scripted translation.
264 QString trans, strans;
265 int cdpos = rawtrans.indexOf(s->theFence);
266 if (cdpos > 0)
267 {
268 // Script fence has been found, strip the scripted from the
269 // ordinary translation.
270 trans = rawtrans.left(cdpos);
271
272 // Scripted translation.
273 strans = rawtrans.mid(cdpos + s->theFence.length());
274
275 // Try to initialize Transcript if not initialized, and script not empty.
276 if ( !s->loadTranscriptCalled && !strans.isEmpty()
277 && locale && locale->useTranscript())
278 {
279 if (KGlobal::hasMainComponent())
280 loadTranscript();
281 else
282 kDebug(173) << QString::fromLatin1("Scripted message {%1} before transcript engine can be loaded.")
283 .arg(shortenMessage(trans));
284 }
285 }
286 else if (cdpos < 0)
287 {
288 // No script fence, use translation as is.
289 trans = rawtrans;
290 }
291 else // cdpos == 0
292 {
293 // The msgstr starts with the script fence, no ordinary translation.
294 // This is not allowed, consider message not translated.
295 kDebug(173) << QString::fromLatin1("Scripted message {%1} without ordinary translation, discarded.")
296 .arg(shortenMessage(trans)) ;
297 trans = selectForEnglish();
298 }
299
300 // Substitute placeholders in ordinary translation.
301 QString final = substituteSimple(trans);
302 // Post-format ordinary translation.
303 final = postFormat(final, lang, QString::fromLatin1(ctxt));
304
305 // If there is also a scripted translation.
306 if (!strans.isEmpty()) {
307 // Evaluate scripted translation.
308 bool fallback;
309 QString sfinal = substituteTranscript(strans, lang, ctry, final, fallback);
310
311 // If any translation produced and no fallback requested.
312 if (!sfinal.isEmpty() && !fallback) {
313 final = postFormat(sfinal, lang, QString::fromLatin1(ctxt));
314 }
315 }
316
317 // Execute any scripted post calls; they cannot modify the final result,
318 // but are used to set states.
319 if (s->ktrs != NULL)
320 {
321 QStringList pcalls = s->ktrs->postCalls(lang);
322 foreach(const QString &pcall, pcalls)
323 postTranscript(pcall, lang, ctry, final);
324 }
325
326 return final;
327}
328
329QString KLocalizedStringPrivate::selectForEnglish () const
330{
331 QString trans;
332
333 if (!plural.isEmpty()) {
334 if (number == 1) {
335 trans = QString::fromUtf8(msg);
336 }
337 else {
338 trans = QString::fromUtf8(plural);
339 }
340 }
341 else {
342 trans = QString::fromUtf8(msg);
343 }
344
345 return trans;
346}
347
348QString KLocalizedStringPrivate::substituteSimple (const QString &trans,
349 const QChar &plchar,
350 bool partial) const
351{
352 #ifdef NDEBUG
353 Q_UNUSED(partial);
354 #endif
355
356 QStringList tsegs; // text segments per placeholder occurrence
357 QList<int> plords; // ordinal numbers per placeholder occurrence
358 #ifndef NDEBUG
359 QVector<int> ords; // indicates which placeholders are present
360 #endif
361 int slen = trans.length();
362 int spos = 0;
363 int tpos = trans.indexOf(plchar);
364 while (tpos >= 0)
365 {
366 int ctpos = tpos;
367
368 tpos++;
369 if (tpos == slen)
370 break;
371
372 if (trans[tpos].digitValue() > 0) // %0 not considered a placeholder
373 {
374 // Get the placeholder ordinal.
375 int plord = 0;
376 while (tpos < slen && trans[tpos].digitValue() >= 0)
377 {
378 plord = 10 * plord + trans[tpos].digitValue();
379 tpos++;
380 }
381 plord--; // ordinals are zero based
382
383 #ifndef NDEBUG
384 // Perhaps enlarge storage for indicators.
385 // Note that QVector<int> will initialize new elements to 0,
386 // as they are supposed to be.
387 if (plord >= ords.size())
388 ords.resize(plord + 1);
389
390 // Indicate that placeholder with computed ordinal is present.
391 ords[plord] = 1;
392 #endif
393
394 // Store text segment prior to placeholder and placeholder number.
395 tsegs.append(trans.mid(spos, ctpos - spos));
396 plords.append(plord);
397
398 // Position of next text segment.
399 spos = tpos;
400 }
401
402 tpos = trans.indexOf(plchar, tpos);
403 }
404 // Store last text segment.
405 tsegs.append(trans.mid(spos));
406
407 #ifndef NDEBUG
408 // Perhaps enlarge storage for plural-number ordinal.
409 if (!plural.isEmpty() && numberOrd >= ords.size())
410 ords.resize(numberOrd + 1);
411
412 // Message might have plural but without plural placeholder, which is an
413 // allowed state. To ease further logic, indicate that plural placeholder
414 // is present anyway if message has plural.
415 if (!plural.isEmpty())
416 ords[numberOrd] = 1;
417 #endif
418
419 // Assemble the final string from text segments and arguments.
420 QString final;
421 for (int i = 0; i < plords.size(); i++)
422 {
423 final.append(tsegs.at(i));
424 if (plords.at(i) >= args.size())
425 // too little arguments
426 {
427 // put back the placeholder
428 final.append(QLatin1Char('%') + QString::number(plords.at(i) + 1));
429 #ifndef NDEBUG
430 if (!partial)
431 // spoof the message
432 final.append(QLatin1String("(I18N_ARGUMENT_MISSING)"));
433 #endif
434 }
435 else
436 // just fine
437 final.append(args.at(plords.at(i)));
438 }
439 final.append(tsegs.last());
440
441 #ifndef NDEBUG
442 if (!partial)
443 {
444 // Check that there are no gaps in numbering sequence of placeholders.
445 bool gaps = false;
446 for (int i = 0; i < ords.size(); i++)
447 if (!ords.at(i))
448 {
449 gaps = true;
450 kDebug(173) << QString::fromLatin1("Placeholder %%1 skipped in message {%2}.")
451 .arg(QString::number(i + 1), shortenMessage(trans));
452 }
453 // If no gaps, check for mismatch between number of unique placeholders and
454 // actually supplied arguments.
455 if (!gaps && ords.size() != args.size())
456 kDebug(173) << QString::fromLatin1("%1 instead of %2 arguments to message {%3} supplied before conversion.")
457 .arg(args.size()).arg(ords.size()).arg(shortenMessage(trans));
458
459 // Some spoofs.
460 if (gaps)
461 final.append(QLatin1String("(I18N_GAPS_IN_PLACEHOLDER_SEQUENCE)"));
462 if (ords.size() < args.size())
463 final.append(QLatin1String("(I18N_EXCESS_ARGUMENTS_SUPPLIED)"));
464 if (!plural.isEmpty() && !numberSet)
465 final.append(QLatin1String("(I18N_PLURAL_ARGUMENT_MISSING)"));
466 }
467 #endif
468
469 return final;
470}
471
472QString KLocalizedStringPrivate::postFormat (const QString &text,
473 const QString &lang,
474 const QString &ctxt) const
475{
476 const KLocalizedStringPrivateStatics *s = staticsKLSP;
477 QMutexLocker lock(kLocaleMutex());
478
479 QString final = text;
480
481 // Transform any semantic markup into visual formatting.
482 if (s->formatters.contains(lang)) {
483 final = s->formatters[lang]->format(final, ctxt);
484 }
485
486 return final;
487}
488
489QString KLocalizedStringPrivate::substituteTranscript (const QString &strans,
490 const QString &lang,
491 const QString &ctry,
492 const QString &final,
493 bool &fallback) const
494{
495 const KLocalizedStringPrivateStatics *s = staticsKLSP;
496 QMutexLocker lock(kLocaleMutex());
497
498 if (s->ktrs == NULL)
499 // Scripting engine not available.
500 return QString();
501
502 // Iterate by interpolations.
503 QString sfinal;
504 fallback = false;
505 int ppos = 0;
506 int tpos = strans.indexOf(s->startInterp);
507 while (tpos >= 0)
508 {
509 // Resolve substitutions in preceding text.
510 QString ptext = substituteSimple(strans.mid(ppos, tpos - ppos),
511 s->scriptPlchar, true);
512 sfinal.append(ptext);
513
514 // Resolve interpolation.
515 QString result;
516 bool fallbackLocal;
517 tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
518 result, fallbackLocal);
519
520 // If there was a problem in parsing the interpolation, cannot proceed
521 // (debug info already reported while parsing).
522 if (tpos < 0) {
523 return QString();
524 }
525 // If fallback has been explicitly requested, indicate global fallback
526 // but proceed with evaluations (other interpolations may set states).
527 if (fallbackLocal) {
528 fallback = true;
529 }
530
531 // Add evaluated interpolation to the text.
532 sfinal.append(result);
533
534 // On to next interpolation.
535 ppos = tpos;
536 tpos = strans.indexOf(s->startInterp, tpos);
537 }
538 // Last text segment.
539 sfinal.append(substituteSimple(strans.mid(ppos), s->scriptPlchar, true));
540
541 // Return empty string if fallback was requested.
542 return fallback ? QString() : sfinal;
543}
544
545int KLocalizedStringPrivate::resolveInterpolation (const QString &strans,
546 int pos,
547 const QString &lang,
548 const QString &ctry,
549 const QString &final,
550 QString &result,
551 bool &fallback) const
552{
553 // pos is the position of opening character sequence.
554 // Returns the position of first character after closing sequence,
555 // or -1 in case of parsing error.
556 // result is set to result of Transcript evaluation.
557 // fallback is set to true if Transcript evaluation requested so.
558
559 KLocalizedStringPrivateStatics *s = staticsKLSP;
560 QMutexLocker lock(kLocaleMutex());
561
562 result.clear();
563 fallback = false;
564
565 // Split interpolation into arguments.
566 QList<QVariant> iargs;
567 int slen = strans.length();
568 int islen = s->startInterp.length();
569 int ielen = s->endInterp.length();
570 int tpos = pos + s->startInterp.length();
571 while (1)
572 {
573 // Skip whitespace.
574 while (tpos < slen && strans[tpos].isSpace()) {
575 ++tpos;
576 }
577 if (tpos == slen) {
578 kDebug(173) << QString::fromLatin1("Unclosed interpolation {%1} in message {%2}.")
579 .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
580 return -1;
581 }
582 if (strans.mid(tpos, ielen) == s->endInterp) {
583 break; // no more arguments
584 }
585
586 // Parse argument: may be concatenated from free and quoted text,
587 // and sub-interpolations.
588 // Free and quoted segments may contain placeholders, substitute them;
589 // recurse into sub-interpolations.
590 // Free segments may be value references, parse and record for
591 // consideration at the end.
592 // Mind backslash escapes throughout.
593 QStringList segs;
594 QVariant vref;
595 while ( !strans[tpos].isSpace()
596 && strans.mid(tpos, ielen) != s->endInterp)
597 {
598 if (strans[tpos] == QLatin1Char('\'')) { // quoted segment
599 QString seg;
600 ++tpos; // skip opening quote
601 // Find closing quote.
602 while (tpos < slen && strans[tpos] != QLatin1Char('\'')) {
603 if (strans[tpos] == QLatin1Char('\\'))
604 ++tpos; // escape next character
605 seg.append(strans[tpos]);
606 ++tpos;
607 }
608 if (tpos == slen) {
609 kDebug(173) << QString::fromLatin1("Unclosed quote in interpolation {%1} in message {%2}.")
610 .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
611 return -1;
612 }
613
614 // Append to list of segments, resolving placeholders.
615 segs.append(substituteSimple(seg, s->scriptPlchar, true));
616
617 ++tpos; // skip closing quote
618 }
619 else if (strans.mid(tpos, islen) == s->startInterp) { // sub-interpolation
620 QString resultLocal;
621 bool fallbackLocal;
622 tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
623 resultLocal, fallbackLocal);
624 if (tpos < 0) { // unrecoverable problem in sub-interpolation
625 // Error reported in the subcall.
626 return tpos;
627 }
628 if (fallbackLocal) { // sub-interpolation requested fallback
629 fallback = true;
630 }
631 segs.append(resultLocal);
632 }
633 else { // free segment
634 QString seg;
635 // Find whitespace, quote, opening or closing sequence.
636 while ( tpos < slen
637 && !strans[tpos].isSpace() && strans[tpos] != QLatin1Char('\'')
638 && strans.mid(tpos, islen) != s->startInterp
639 && strans.mid(tpos, ielen) != s->endInterp)
640 {
641 if (strans[tpos] == QLatin1Char('\\'))
642 ++tpos; // escape next character
643 seg.append(strans[tpos]);
644 ++tpos;
645 }
646 if (tpos == slen) {
647 kDebug(173) << QString::fromLatin1("Non-terminated interpolation {%1} in message {%2}.")
648 .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
649 return -1;
650 }
651
652 // The free segment may look like a value reference;
653 // in that case, record which value it would reference,
654 // and add verbatim to the segment list.
655 // Otherwise, do a normal substitution on the segment.
656 vref = segmentToValue(seg);
657 if (vref.isValid()) {
658 segs.append(seg);
659 }
660 else {
661 segs.append(substituteSimple(seg, s->scriptPlchar, true));
662 }
663 }
664 }
665
666 // Append this argument to rest of the arguments.
667 // If the there was a single text segment and it was a proper value
668 // reference, add it instead of the joined segments.
669 // Otherwise, add the joined segments.
670 if (segs.size() == 1 && vref.isValid()) {
671 iargs.append(vref);
672 }
673 else {
674 iargs.append(segs.join(QString()));
675 }
676 }
677 tpos += ielen; // skip to first character after closing sequence
678
679 // NOTE: Why not substitute placeholders (via substituteSimple) in one
680 // global pass, then handle interpolations in second pass? Because then
681 // there is the danger of substituted text or sub-interpolations producing
682 // quotes and escapes themselves, which would mess up the parsing.
683
684 // Evaluate interpolation.
685 QString msgctxt = QString::fromUtf8(ctxt);
686 QString msgid = QString::fromUtf8(msg);
687 QString scriptError;
688 bool fallbackLocal;
689 result = s->ktrs->eval(iargs, lang, ctry,
690 msgctxt, dynctxt, msgid,
691 args, vals, final, s->scriptModulesToLoad,
692 scriptError, fallbackLocal);
693 // s->scriptModulesToLoad will be cleared during the call.
694
695 if (fallbackLocal) { // evaluation requested fallback
696 fallback = true;
697 }
698 if (!scriptError.isEmpty()) { // problem with evaluation
699 fallback = true; // also signal fallback
700 if (!scriptError.isEmpty()) {
701 kDebug(173) << QString::fromLatin1("Interpolation {%1} in {%2} failed: %3")
702 .arg(strans.mid(pos, tpos - pos), shortenMessage(strans), scriptError);
703 }
704 }
705
706 return tpos;
707}
708
709QVariant KLocalizedStringPrivate::segmentToValue (const QString &seg) const
710{
711 const KLocalizedStringPrivateStatics *s = staticsKLSP;
712 QMutexLocker lock(kLocaleMutex());
713
714 // Return invalid variant if segment is either not a proper
715 // value reference, or the reference is out of bounds.
716
717 // Value reference must start with a special character.
718 if (seg.left(1) != s->scriptVachar) {
719 return QVariant();
720 }
721
722 // Reference number must start with 1-9.
723 // (If numstr is empty, toInt() will return 0.)
724 QString numstr = seg.mid(1);
725 if (numstr.left(1).toInt() < 1) {
726 return QVariant();
727 }
728
729 // Number must be valid and in bounds.
730 bool ok;
731 int index = numstr.toInt(&ok) - 1;
732 if (!ok || index >= vals.size()) {
733 return QVariant();
734 }
735
736 // Passed all hoops.
737 return vals.at(index);
738}
739
740QString KLocalizedStringPrivate::postTranscript (const QString &pcall,
741 const QString &lang,
742 const QString &ctry,
743 const QString &final) const
744{
745 KLocalizedStringPrivateStatics *s = staticsKLSP;
746 QMutexLocker lock(kLocaleMutex());
747
748 if (s->ktrs == NULL)
749 // Scripting engine not available.
750 // (Though this cannot happen, we wouldn't be here then.)
751 return QString();
752
753 // Resolve the post call.
754 QList<QVariant> iargs;
755 iargs.append(pcall);
756 QString msgctxt = QString::fromUtf8(ctxt);
757 QString msgid = QString::fromUtf8(msg);
758 QString scriptError;
759 bool fallback;
760 QString dummy = s->ktrs->eval(iargs, lang, ctry,
761 msgctxt, dynctxt, msgid,
762 args, vals, final, s->scriptModulesToLoad,
763 scriptError, fallback);
764 // s->scriptModulesToLoad will be cleared during the call.
765
766 // If the evaluation went wrong.
767 if (!scriptError.isEmpty())
768 {
769 kDebug(173) << QString::fromLatin1("Post call {%1} for message {%2} failed: %3")
770 .arg(pcall, shortenMessage(msgid), scriptError);
771 return QString();
772 }
773
774 return final;
775}
776
777static QString wrapNum (const QString &tag, const QString &numstr,
778 int fieldWidth, const QChar &fillChar)
779{
780 QString optag;
781 if (fieldWidth != 0) {
782 QString fillString = KuitSemantics::escape(fillChar);
783 optag = QString::fromLatin1("<%1 width='%2' fill='%3'>")
784 .arg(tag, QString::number(fieldWidth), fillString);
785 } else {
786 optag = QString::fromLatin1("<%1>").arg(tag);
787 }
788 QString cltag = QString::fromLatin1("</%1>").arg(tag);
789 return optag + numstr + cltag;
790}
791
792KLocalizedString KLocalizedString::subs (int a, int fieldWidth, int base,
793 const QChar &fillChar) const
794{
795 KLocalizedString kls(*this);
796 if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
797 kls.d->number = static_cast<pluraln>(abs(a));
798 kls.d->numberSet = true;
799 kls.d->numberOrd = d->args.size();
800 }
801 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
802 fieldWidth, fillChar));
803 kls.d->vals.append(static_cast<intn>(a));
804 return kls;
805}
806
807KLocalizedString KLocalizedString::subs (uint a, int fieldWidth, int base,
808 const QChar &fillChar) const
809{
810 KLocalizedString kls(*this);
811 if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
812 kls.d->number = static_cast<pluraln>(a);
813 kls.d->numberSet = true;
814 kls.d->numberOrd = d->args.size();
815 }
816 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
817 fieldWidth, fillChar));
818 kls.d->vals.append(static_cast<uintn>(a));
819 return kls;
820}
821
822KLocalizedString KLocalizedString::subs (long a, int fieldWidth, int base,
823 const QChar &fillChar) const
824{
825 KLocalizedString kls(*this);
826 if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
827 kls.d->number = static_cast<pluraln>(abs(a));
828 kls.d->numberSet = true;
829 kls.d->numberOrd = d->args.size();
830 }
831 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
832 fieldWidth, fillChar));
833 kls.d->vals.append(static_cast<intn>(a));
834 return kls;
835}
836
837KLocalizedString KLocalizedString::subs (ulong a, int fieldWidth, int base,
838 const QChar &fillChar) const
839{
840 KLocalizedString kls(*this);
841 if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
842 kls.d->number = static_cast<pluraln>(a);
843 kls.d->numberSet = true;
844 kls.d->numberOrd = d->args.size();
845 }
846 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
847 fieldWidth, fillChar));
848 kls.d->vals.append(static_cast<uintn>(a));
849 return kls;
850}
851
852KLocalizedString KLocalizedString::subs (qlonglong a, int fieldWidth, int base,
853 const QChar &fillChar) const
854{
855 KLocalizedString kls(*this);
856 if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
857 kls.d->number = static_cast<pluraln>(qAbs(a));
858 kls.d->numberSet = true;
859 kls.d->numberOrd = d->args.size();
860 }
861 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
862 fieldWidth, fillChar));
863 kls.d->vals.append(static_cast<intn>(a));
864 return kls;
865}
866
867KLocalizedString KLocalizedString::subs (qulonglong a, int fieldWidth, int base,
868 const QChar &fillChar) const
869{
870 KLocalizedString kls(*this);
871 if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
872 kls.d->number = static_cast<pluraln>(a);
873 kls.d->numberSet = true;
874 kls.d->numberOrd = d->args.size();
875 }
876 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
877 fieldWidth, fillChar));
878 kls.d->vals.append(static_cast<uintn>(a));
879 return kls;
880}
881
882KLocalizedString KLocalizedString::subs (double a, int fieldWidth,
883 char format, int precision,
884 const QChar &fillChar) const
885{
886 KLocalizedString kls(*this);
887 kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMREAL),
888 QString::number(a, format, precision),
889 fieldWidth, fillChar));
890 kls.d->vals.append(static_cast<realn>(a));
891 return kls;
892}
893
894KLocalizedString KLocalizedString::subs (QChar a, int fieldWidth,
895 const QChar &fillChar) const
896{
897 KLocalizedString kls(*this);
898 kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
899 kls.d->vals.append(QString(a));
900 return kls;
901}
902
903KLocalizedString KLocalizedString::subs (const QString &a, int fieldWidth,
904 const QChar &fillChar) const
905{
906 KLocalizedString kls(*this);
907 // if (!KuitSemantics::mightBeRichText(a)) { ...
908 // Do not try to auto-escape non-rich-text alike arguments;
909 // breaks compatibility with 4.0. Perhaps for KDE 5?
910 // Perhaps bad idea alltogether (too much surprise)?
911 kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
912 kls.d->vals.append(a);
913 return kls;
914}
915
916KLocalizedString KLocalizedString::inContext (const QString &key,
917 const QString &text) const
918{
919 KLocalizedString kls(*this);
920 kls.d->dynctxt[key] = text;
921 return kls;
922}
923
924KLocalizedString ki18n (const char* msg)
925{
926 return KLocalizedString(NULL, msg, NULL);
927}
928
929KLocalizedString ki18nc (const char* ctxt, const char *msg)
930{
931 return KLocalizedString(ctxt, msg, NULL);
932}
933
934KLocalizedString ki18np (const char* singular, const char* plural)
935{
936 return KLocalizedString(NULL, singular, plural);
937}
938
939KLocalizedString ki18ncp (const char* ctxt,
940 const char* singular, const char* plural)
941{
942 return KLocalizedString(ctxt, singular, plural);
943}
944
945extern "C"
946{
947 typedef KTranscript *(*InitFunc)();
948}
949
950void KLocalizedStringPrivate::loadTranscript ()
951{
952 KLocalizedStringPrivateStatics *s = staticsKLSP;
953 QMutexLocker lock(kLocaleMutex());
954
955 s->loadTranscriptCalled = true;
956 s->ktrs = NULL; // null indicates that Transcript is not available
957
958 KLibrary lib(QLatin1String("ktranscript"));
959 if (!lib.load()) {
960 kDebug(173) << "Cannot load transcript plugin:" << lib.errorString();
961 return;
962 }
963
964 InitFunc initf = (InitFunc) lib.resolveFunction("load_transcript");
965 if (!initf) {
966 lib.unload();
967 kDebug(173) << "Cannot find function load_transcript in transcript plugin.";
968 return;
969 }
970
971 s->ktrs = initf();
972}
973
974void KLocalizedString::notifyCatalogsUpdated (const QStringList &languages,
975 const QList<KCatalogName> &catalogs)
976{
977 KLocalizedStringPrivate::notifyCatalogsUpdated(languages, catalogs);
978}
979
980void KLocalizedStringPrivate::notifyCatalogsUpdated (const QStringList &languages,
981 const QList<KCatalogName> &catalogs)
982{
983 if (staticsKLSP.isDestroyed()) {
984 return;
985 }
986 KLocalizedStringPrivateStatics *s = staticsKLSP;
987 // Very important: do not the mutex here.
988 //QMutexLocker lock(kLocaleMutex());
989
990 // Find script modules for all included language/catalogs that have them,
991 // and remember their paths.
992 // A more specific module may reference the calls from a less specific,
993 // and the catalog list is ordered from more to less specific. Therefore,
994 // work on reversed list of catalogs.
995 foreach (const QString &lang, languages) {
996 for (int i = catalogs.size() - 1; i >= 0; --i) {
997 const KCatalogName &cat(catalogs[i]);
998
999 // Assemble module's relative path.
1000 QString modrpath = lang + QLatin1Char('/') + s->scriptDir + QLatin1Char('/')
1001 + cat.name + QLatin1Char('/') + cat.name + QLatin1String(".js");
1002
1003 // Try to find this module.
1004 QString modapath = KStandardDirs::locate("locale", modrpath);
1005
1006 // If the module exists and hasn't been already included.
1007 if ( !modapath.isEmpty()
1008 && !s->scriptModules[lang].contains(cat.name))
1009 {
1010 // Indicate that the module has been considered.
1011 s->scriptModules[lang].append(cat.name);
1012
1013 // Store the absolute path and language of the module,
1014 // to load on next script evaluation.
1015 QStringList mod;
1016 mod.append(modapath);
1017 mod.append(lang);
1018 s->scriptModulesToLoad.append(mod);
1019 }
1020 }
1021 }
1022
1023 // Create visual formatters for each new language.
1024 foreach (const QString &lang, languages) {
1025 if (!s->formatters.contains(lang)) {
1026 s->formatters.insert(lang, new KuitSemantics(lang));
1027 }
1028 }
1029}
KLibrary
Thin wrapper around QLibrary; you should rarely use this directly, see KPluginLoader for higher-level...
Definition: klibrary.h:39
KLibrary::unload
bool unload()
Definition: klibrary.h:79
KLibrary::resolveFunction
void_function_ptr resolveFunction(const char *name)
Looks up a symbol from the library.
Definition: klibrary.cpp:181
KLocale
KLocale provides support for country specific stuff like the national language.
Definition: klocale.h:70
KLocale::translateRawFrom
void translateRawFrom(const char *catname, const char *msg, QString *lang, QString *trans) const
Definition: klocale.cpp:158
KLocale::defaultLanguage
static QString defaultLanguage()
Returns the name of the internal language.
Definition: klocale.cpp:615
KLocale::country
QString country() const
Returns the country code of the country where the user lives.
Definition: klocale.cpp:116
KLocale::useTranscript
bool useTranscript() const
Reports whether evaluation of translation scripts is enabled.
Definition: klocale.cpp:630
KLocalizedString
Class for producing and handling localized messages.
Definition: klocalizedstring.h:300
KLocalizedString::subs
KLocalizedString subs(int a, int fieldWidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const
Substitutes an int argument into the message.
Definition: klocalizedstring.cpp:792
KLocalizedString::KLocalizedString
KLocalizedString()
Constructs an empty message, which is not valid for finalization.
Definition: klocalizedstring.cpp:148
KLocalizedString::~KLocalizedString
~KLocalizedString()
Destructor.
Definition: klocalizedstring.cpp:182
KLocalizedString::toString
QString toString() const
Finalizes the translation, creates QString with placeholders substituted.
Definition: klocalizedstring.cpp:192
KLocalizedString::operator=
KLocalizedString & operator=(const KLocalizedString &rhs)
Assignment operator.
Definition: klocalizedstring.cpp:173
KLocalizedString::inContext
KLocalizedString inContext(const QString &key, const QString &text) const
Adds dynamic context to the message.
Definition: klocalizedstring.cpp:916
KLocalizedString::isEmpty
bool isEmpty() const
Checks whether the message is empty.
Definition: klocalizedstring.cpp:187
KLocalizedString::notifyCatalogsUpdated
static void notifyCatalogsUpdated(const QStringList &languages, const QList< KCatalogName > &catalogs)
Definition: klocalizedstring.cpp:974
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
This function is just for convenience.
Definition: kstandarddirs.cpp:2091
KTranscript
class for supporting programmable translations
Definition: ktranscript_p.h:39
KuitSemantics
class for formatting semantic markup in UI messages
Definition: kuitsemantics_p.h:39
KuitSemantics::escape
static QString escape(const QString &text)
Convert &, ", ', <, > characters into XML entities &, <, >, ', ", respectively.
Definition: kuitsemantics.cpp:1633
QHash
Definition: ksycocafactory.h:28
QList
Definition: kaboutdata.h:33
QStringList
QString
QVariant
double
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
Definition: kglobal.h:221
kDebug
#define kDebug
Definition: kdebug.h:316
kcatalogname_p.h
kdebug.h
kglobal.h
klibrary.h
klocale.h
kLocaleMutex
QMutex * kLocaleMutex()
Definition: klocale_kde.cpp:3319
klocale_p.h
ki18n
KLocalizedString ki18n(const char *msg)
Creates localized string from a given message.
Definition: klocalizedstring.cpp:924
shortenMessage
static QString shortenMessage(const QString &str)
Definition: klocalizedstring.cpp:43
pluraln
qulonglong pluraln
Definition: klocalizedstring.cpp:52
ki18ncp
KLocalizedString ki18ncp(const char *ctxt, const char *singular, const char *plural)
Creates localized string from a given plural and singular form, with added context.
Definition: klocalizedstring.cpp:939
uintn
qulonglong uintn
Definition: klocalizedstring.cpp:54
realn
double realn
Definition: klocalizedstring.cpp:55
InitFunc
KTranscript *(* InitFunc)()
Definition: klocalizedstring.cpp:947
ki18nc
KLocalizedString ki18nc(const char *ctxt, const char *msg)
Creates localized string from a given message, with added context.
Definition: klocalizedstring.cpp:929
ki18np
KLocalizedString ki18np(const char *singular, const char *plural)
Creates localized string from a given plural and singular form.
Definition: klocalizedstring.cpp:934
wrapNum
static QString wrapNum(const QString &tag, const QString &numstr, int fieldWidth, const QChar &fillChar)
Definition: klocalizedstring.cpp:777
intn
qlonglong intn
Definition: klocalizedstring.cpp:53
klocalizedstring.h
kstandarddirs.h
ktranscript_p.h
kuitsemantics_p.h
KUIT_NUMREAL
#define KUIT_NUMREAL
Definition: kuitsemantics_p.h:88
KUIT_NUMINTG
#define KUIT_NUMINTG
Definition: kuitsemantics_p.h:87
KGlobal::hasMainComponent
bool hasMainComponent()
Definition: kglobal.cpp:151
KGlobal::locale
KLocale * locale()
Returns the global locale object.
Definition: kglobal.cpp:170
KCatalogName
Definition: kcatalogname_p.h:26
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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.14.38 API Reference

Skip menu "kdelibs-4.14.38 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