34 #include <QMutexLocker>
35 #include <QStringList>
45 const int maxlen = 20;
46 if (str.length() <= maxlen)
49 return str.left(maxlen).append(QLatin1String(
"..."));
57 class KLocalizedStringPrivateStatics;
59 class KLocalizedStringPrivate
74 QString selectForEnglish ()
const;
76 const QChar &plchar = QLatin1Char(
'%'),
77 bool partial =
false)
const;
85 bool &fallback)
const;
86 int resolveInterpolation (
const QString &trans,
int pos,
91 bool &fallback)
const;
100 static void loadTranscript ();
103 class KLocalizedStringPrivateStatics
110 const QChar scriptPlchar;
111 const QChar scriptVachar;
117 bool loadTranscriptCalled;
122 KLocalizedStringPrivateStatics () :
123 theFence(QLatin1String(
"|/|")),
124 startInterp(QLatin1String(
"$[")),
125 endInterp(QLatin1String(
"]")),
126 scriptPlchar(QLatin1Char(
'%')),
127 scriptVachar(QLatin1Char(
'^')),
129 scriptDir(QLatin1String(
"LC_SCRIPTS")),
131 scriptModulesToLoad(),
133 loadTranscriptCalled(false),
139 ~KLocalizedStringPrivateStatics ()
143 qDeleteAll(formatters);
149 : d(new KLocalizedStringPrivate)
151 d->numberSet =
false;
157 const char *msg,
const char *plural)
158 : d(new KLocalizedStringPrivate)
163 d->numberSet =
false;
169 : d(new KLocalizedStringPrivate(*rhs.d))
189 return d->msg.isEmpty();
204 return d->toString(locale, NULL);
208 const QString &catalogName)
const
210 return d->toString(locale, &catalogName);
214 const QString *catalogName)
const
216 const KLocalizedStringPrivateStatics *s = staticsKLSP;
223 kDebug(173) <<
"Trying to convert empty KLocalizedString to QString.";
225 return QString::fromLatin1(
"(I18N_EMPTY_MESSAGE)");
232 if (!plural.isEmpty() && !numberSet)
233 kDebug(173) << QString::fromLatin1(
"Plural argument to message {%1} not supplied before conversion.")
239 if (catalogName != NULL) {
240 catname = catalogName->toUtf8();
242 if (locale != NULL) {
243 if (!ctxt.isEmpty() && !plural.isEmpty()) {
246 }
else if (!plural.isEmpty()) {
249 }
else if (!ctxt.isEmpty()) {
259 ctry = QLatin1Char(
'C');
260 rawtrans = selectForEnglish();
265 int cdpos = rawtrans.indexOf(s->theFence);
270 trans = rawtrans.left(cdpos);
273 strans = rawtrans.mid(cdpos + s->theFence.length());
276 if ( !s->loadTranscriptCalled && !strans.isEmpty()
282 kDebug(173) << QString::fromLatin1(
"Scripted message {%1} before transcript engine can be loaded.")
295 kDebug(173) << QString::fromLatin1(
"Scripted message {%1} without ordinary translation, discarded.")
297 trans = selectForEnglish();
301 QString final = substituteSimple(trans);
303 final = postFormat(
final, lang, QString::fromLatin1(ctxt));
306 if (!strans.isEmpty()) {
309 QString sfinal = substituteTranscript(strans, lang, ctry,
final, fallback);
312 if (!sfinal.isEmpty() && !fallback) {
313 final = postFormat(sfinal, lang, QString::fromLatin1(ctxt));
322 foreach(
const QString &pcall, pcalls)
323 postTranscript(pcall, lang, ctry,
final);
329 QString KLocalizedStringPrivate::selectForEnglish ()
const
333 if (!plural.isEmpty()) {
335 trans = QString::fromUtf8(msg);
338 trans = QString::fromUtf8(plural);
342 trans = QString::fromUtf8(msg);
348 QString KLocalizedStringPrivate::substituteSimple (
const QString &trans,
361 int slen = trans.length();
363 int tpos = trans.indexOf(plchar);
372 if (trans[tpos].digitValue() > 0)
376 while (tpos < slen && trans[tpos].digitValue() >= 0)
378 plord = 10 * plord + trans[tpos].digitValue();
387 if (plord >= ords.size())
388 ords.resize(plord + 1);
395 tsegs.append(trans.mid(spos, ctpos - spos));
396 plords.append(plord);
402 tpos = trans.indexOf(plchar, tpos);
405 tsegs.append(trans.mid(spos));
409 if (!plural.isEmpty() && numberOrd >= ords.size())
410 ords.resize(numberOrd + 1);
415 if (!plural.isEmpty())
421 for (
int i = 0; i < plords.size(); i++)
423 final.append(tsegs.at(i));
424 if (plords.at(i) >= args.size())
428 final.append(QLatin1Char(
'%') + QString::number(plords.at(i) + 1));
432 final.append(QLatin1String(
"(I18N_ARGUMENT_MISSING)"));
437 final.append(args.at(plords.at(i)));
439 final.append(tsegs.last());
446 for (
int i = 0; i < ords.size(); i++)
450 kDebug(173) << QString::fromLatin1(
"Placeholder %%1 skipped in message {%2}.")
455 if (!gaps && ords.size() != args.size())
456 kDebug(173) << QString::fromLatin1(
"%1 instead of %2 arguments to message {%3} supplied before conversion.")
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)"));
476 const KLocalizedStringPrivateStatics *s = staticsKLSP;
482 if (s->formatters.contains(lang)) {
483 final = s->formatters[lang]->format(
final, ctxt);
489 QString KLocalizedStringPrivate::substituteTranscript (
const QString &strans,
493 bool &fallback)
const
495 const KLocalizedStringPrivateStatics *s = staticsKLSP;
506 int tpos = strans.indexOf(s->startInterp);
510 QString ptext = substituteSimple(strans.mid(ppos, tpos - ppos),
511 s->scriptPlchar,
true);
512 sfinal.append(ptext);
517 tpos = resolveInterpolation(strans, tpos, lang, ctry,
final,
518 result, fallbackLocal);
532 sfinal.append(result);
536 tpos = strans.indexOf(s->startInterp, tpos);
539 sfinal.append(substituteSimple(strans.mid(ppos), s->scriptPlchar,
true));
542 return fallback ?
QString() : sfinal;
545 int KLocalizedStringPrivate::resolveInterpolation (
const QString &strans,
551 bool &fallback)
const
559 KLocalizedStringPrivateStatics *s = staticsKLSP;
567 int slen = strans.length();
568 int islen = s->startInterp.length();
569 int ielen = s->endInterp.length();
570 int tpos = pos + s->startInterp.length();
574 while (tpos < slen && strans[tpos].isSpace()) {
578 kDebug(173) << QString::fromLatin1(
"Unclosed interpolation {%1} in message {%2}.")
582 if (strans.mid(tpos, ielen) == s->endInterp) {
595 while ( !strans[tpos].isSpace()
596 && strans.mid(tpos, ielen) != s->endInterp)
598 if (strans[tpos] == QLatin1Char(
'\'')) {
602 while (tpos < slen && strans[tpos] != QLatin1Char(
'\'')) {
603 if (strans[tpos] == QLatin1Char(
'\\'))
605 seg.append(strans[tpos]);
609 kDebug(173) << QString::fromLatin1(
"Unclosed quote in interpolation {%1} in message {%2}.")
615 segs.append(substituteSimple(seg, s->scriptPlchar,
true));
619 else if (strans.mid(tpos, islen) == s->startInterp) {
622 tpos = resolveInterpolation(strans, tpos, lang, ctry,
final,
623 resultLocal, fallbackLocal);
631 segs.append(resultLocal);
637 && !strans[tpos].isSpace() && strans[tpos] != QLatin1Char(
'\'')
638 && strans.mid(tpos, islen) != s->startInterp
639 && strans.mid(tpos, ielen) != s->endInterp)
641 if (strans[tpos] == QLatin1Char(
'\\'))
643 seg.append(strans[tpos]);
647 kDebug(173) << QString::fromLatin1(
"Non-terminated interpolation {%1} in message {%2}.")
656 vref = segmentToValue(seg);
657 if (vref.isValid()) {
661 segs.append(substituteSimple(seg, s->scriptPlchar,
true));
670 if (segs.size() == 1 && vref.isValid()) {
674 iargs.append(segs.join(
QString()));
685 QString msgctxt = QString::fromUtf8(ctxt);
686 QString msgid = QString::fromUtf8(msg);
689 result = s->ktrs->eval(iargs, lang, ctry,
690 msgctxt, dynctxt, msgid,
691 args, vals,
final, s->scriptModulesToLoad,
692 scriptError, fallbackLocal);
698 if (!scriptError.isEmpty()) {
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);
709 QVariant KLocalizedStringPrivate::segmentToValue (
const QString &seg)
const
711 const KLocalizedStringPrivateStatics *s = staticsKLSP;
718 if (seg.left(1) != s->scriptVachar) {
725 if (numstr.left(1).toInt() < 1) {
731 int index = numstr.toInt(&ok) - 1;
732 if (!ok || index >= vals.size()) {
737 return vals.at(index);
740 QString KLocalizedStringPrivate::postTranscript (
const QString &pcall,
745 KLocalizedStringPrivateStatics *s = staticsKLSP;
756 QString msgctxt = QString::fromUtf8(ctxt);
757 QString msgid = QString::fromUtf8(msg);
760 QString dummy = s->ktrs->eval(iargs, lang, ctry,
761 msgctxt, dynctxt, msgid,
762 args, vals,
final, s->scriptModulesToLoad,
763 scriptError, fallback);
767 if (!scriptError.isEmpty())
769 kDebug(173) << QString::fromLatin1(
"Post call {%1} for message {%2} failed: %3")
778 int fieldWidth,
const QChar &fillChar)
781 if (fieldWidth != 0) {
783 optag = QString::fromLatin1(
"<%1 width='%2' fill='%3'>")
784 .arg(tag, QString::number(fieldWidth), fillString);
786 optag = QString::fromLatin1(
"<%1>").arg(tag);
788 QString cltag = QString::fromLatin1(
"</%1>").arg(tag);
789 return optag + numstr + cltag;
793 const QChar &fillChar)
const
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();
802 fieldWidth, fillChar));
803 kls.d->vals.append(static_cast<intn>(a));
808 const QChar &fillChar)
const
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();
817 fieldWidth, fillChar));
818 kls.d->vals.append(static_cast<uintn>(a));
823 const QChar &fillChar)
const
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();
832 fieldWidth, fillChar));
833 kls.d->vals.append(static_cast<intn>(a));
838 const QChar &fillChar)
const
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();
847 fieldWidth, fillChar));
848 kls.d->vals.append(static_cast<uintn>(a));
853 const QChar &fillChar)
const
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();
862 fieldWidth, fillChar));
863 kls.d->vals.append(static_cast<intn>(a));
868 const QChar &fillChar)
const
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();
877 fieldWidth, fillChar));
878 kls.d->vals.append(static_cast<uintn>(a));
883 char format,
int precision,
884 const QChar &fillChar)
const
888 QString::number(a, format, precision),
889 fieldWidth, fillChar));
890 kls.d->vals.append(static_cast<realn>(a));
895 const QChar &fillChar)
const
898 kls.d->args.append(QString::fromLatin1(
"%1").arg(a, fieldWidth, fillChar));
899 kls.d->vals.append(
QString(a));
904 const QChar &fillChar)
const
911 kls.d->args.append(QString::fromLatin1(
"%1").arg(a, fieldWidth, fillChar));
912 kls.d->vals.append(a);
920 kls.d->dynctxt[key] = text;
940 const char* singular,
const char* plural)
950 void KLocalizedStringPrivate::loadTranscript ()
952 KLocalizedStringPrivateStatics *s = staticsKLSP;
955 s->loadTranscriptCalled =
true;
958 KLibrary lib(QLatin1String(
"ktranscript"));
960 kDebug(173) <<
"Cannot load transcript plugin:" << lib.errorString();
967 kDebug(173) <<
"Cannot find function load_transcript in transcript plugin.";
977 KLocalizedStringPrivate::notifyCatalogsUpdated(languages, catalogs);
980 void KLocalizedStringPrivate::notifyCatalogsUpdated (
const QStringList &languages,
983 if (staticsKLSP.isDestroyed()) {
986 KLocalizedStringPrivateStatics *s = staticsKLSP;
995 foreach (
const QString &lang, languages) {
996 for (
int i = catalogs.size() - 1; i >= 0; --i) {
1000 QString modrpath = lang + QLatin1Char(
'/') + s->scriptDir + QLatin1Char(
'/')
1001 + cat.name + QLatin1Char(
'/') + cat.name + QLatin1String(
".js");
1007 if ( !modapath.isEmpty()
1008 && !s->scriptModules[lang].contains(cat.name))
1011 s->scriptModules[lang].append(cat.name);
1016 mod.append(modapath);
1018 s->scriptModulesToLoad.append(mod);
1024 foreach (
const QString &lang, languages) {
1025 if (!s->formatters.contains(lang)) {
static void notifyCatalogsUpdated(const QStringList &languages, const QList< KCatalogName > &catalogs)
QString toString() const
Finalizes the translation, creates QString with placeholders substituted.
static QString escape(const QString &text)
Convert &, ", ', <, > characters into XML entities &, <, >, ', ", respectively.
KTranscript *(* InitFunc)()
KLocalizedString ki18n(const char *msg)
Creates localized string from a given message.
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
This function is just for convenience.
class for formatting semantic markup in UI messages
static QString shortenMessage(const QString &str)
~KLocalizedString()
Destructor.
KLocalizedString inContext(const QString &key, const QString &text) const
Adds dynamic context to the message.
bool useTranscript() const
Reports whether evaluation of translation scripts is enabled.
KLocalizedString ki18np(const char *singular, const char *plural)
Creates localized string from a given plural and singular form.
bool isEmpty() const
Checks whether the message is empty.
Thin wrapper around QLibrary; you should rarely use this directly, see KPluginLoader for higher-level...
QString country() const
Returns the country code of the country where the user lives.
void translateRawFrom(const char *catname, const char *msg, QString *lang, QString *trans) const
KLocalizedString ki18ncp(const char *ctxt, const char *singular, const char *plural)
Creates localized string from a given plural and singular form, with added context.
KLocale * locale()
Returns the global locale object.
void_function_ptr resolveFunction(const char *name)
Looks up a symbol from the library.
KLocale provides support for country specific stuff like the national language.
KLocalizedString ki18nc(const char *ctxt, const char *msg)
Creates localized string from a given message, with added context.
class for supporting programmable translations
KLocalizedString & operator=(const KLocalizedString &rhs)
Assignment operator.
KLocalizedString subs(int a, int fieldWidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const
Substitutes an int argument into the message.
KLocalizedString()
Constructs an empty message, which is not valid for finalization.
Class for producing and handling localized messages.
static QString defaultLanguage()
Returns the name of the internal language.
static QString wrapNum(const QString &tag, const QString &numstr, int fieldWidth, const QChar &fillChar)