File indexing completed on 2024-04-21 03:54:21
0001 /* 0002 SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #ifndef KLAZYLOCALIZEDSTRING_H 0007 #define KLAZYLOCALIZEDSTRING_H 0008 0009 #include "klocalizedstring.h" 0010 0011 #include <cstddef> 0012 0013 /** 0014 * @class KLazyLocalizedString klazylocalizedstring.h <KLazyLocalizedString> 0015 * 0016 * Lazy-initialized variant of KLocalizedString. 0017 * 0018 * This is a safer replacement for the I18N_NOOP set of macros and allows 0019 * marking strings for extraction without runtime-initializing KLocalizedString instances, 0020 * for storing in static data tables. 0021 * 0022 * Instances of KLazyLocalizedString are not created directly, unless they should be empty. 0023 * Instead they have to be obtained via the kli18n* functions (similar to KLocalizedString 0024 * and the ki18n* functions). 0025 * 0026 * Example usage in a static message table: 0027 * @code 0028 * struct { 0029 * MyClass::VehicleType type; 0030 * KLazyLocalizedString msg; 0031 * } static constexpr const vehicle_msg_table[] = { 0032 * { MyClass::Train, kli18np("%1 train", "%1 trains") }, 0033 * { MyClass::Bus, kli18ncp("the vehicle, not the USB one", "%1 bus", "%1 buses") }, 0034 * ... 0035 * }; 0036 * 0037 * ... 0038 * 0039 * const auto it = std::find_if(std::begin(vehicle_msg_table), std::end(vehicle_msg_table), [vehicleType](const auto &m) { return m.type == vehicleType; }); 0040 * QString translatedMessage = (*it).msg.subs(vehicleCount).toString(); 0041 * @endcode 0042 * 0043 * @note KLazyLocalizedString is primarily meant for storage in e.g. message tables, 0044 * not for use in API, especially not across translation domains. This is due to 0045 * it not carrying the translation domain in which it was created, but using the 0046 * active translation domain at the point of converting to a KLocalizedString. 0047 * 0048 * @since 5.89 0049 */ 0050 class KLazyLocalizedString 0051 { 0052 public: 0053 /** 0054 * Construct an empty message. 0055 * 0056 * Direct construction is used when e.g. a KLazyLocalizedString field in 0057 * a data table needs to be set, but there is not message to be used. 0058 * Directly constructed instances are not valid for 0059 * finalization by \c toString methods. 0060 * 0061 * \see isEmpty 0062 */ 0063 constexpr inline KLazyLocalizedString() = default; 0064 0065 /** Convert to a KLocalizedString to actually perform the translation and obtain a concrete 0066 * localized string. 0067 * 0068 * The translation domain active at this point will be used. This means this has to be 0069 * called in the same translation domain the corresponding @c kli18n call is in. 0070 */ 0071 Q_REQUIRED_RESULT inline operator KLocalizedString() const 0072 { 0073 if (!m_text) { 0074 return KLocalizedString(); 0075 } 0076 #ifdef TRANSLATION_DOMAIN 0077 return KLocalizedString(TRANSLATION_DOMAIN, m_context, m_text, m_plural, m_markupAware); 0078 #else 0079 return KLocalizedString(nullptr, m_context, m_text, m_plural, m_markupAware); 0080 #endif 0081 } 0082 0083 /** 0084 * Check whether the message is empty. 0085 * 0086 * The message is considered empty if the object was constructed 0087 * via the default constructor. 0088 * 0089 * Empty messages are not valid for finalization. 0090 * The behavior of calling toString() on them is undefined. 0091 * In debug mode, an error mark may appear in the returned string. 0092 * 0093 * \return \c true if the message is empty, \c false otherwise 0094 */ 0095 Q_REQUIRED_RESULT constexpr inline bool isEmpty() const 0096 { 0097 return (m_text == nullptr) || (m_text[0] == '\0'); 0098 } 0099 0100 /** Returns the raw untranslated text as passed to @p kli18n*. */ 0101 Q_REQUIRED_RESULT constexpr inline const char *untranslatedText() const 0102 { 0103 return m_text; 0104 } 0105 0106 /** 0107 * Finalize the translation. 0108 * 0109 * Creates translated QString. If the string has placeholders, 0110 * make sure to call instead \c KLazyLocalizedString::subs and 0111 * further \c KLocalizedString::subs methods before finalizing. 0112 * Translated text is searched for based on the global locale. 0113 * 0114 * \return finalized translation 0115 */ 0116 Q_REQUIRED_RESULT inline QString toString() const 0117 { 0118 return this->operator KLocalizedString().toString(); 0119 } 0120 0121 /** 0122 * Like toString(), but look for translation only in given languages. 0123 * 0124 * Given languages override languages defined by the global locale. 0125 * If \p languages is empty, original message is returned. 0126 * 0127 * \param languages list of language codes (by decreasing priority) 0128 * \return finalized translation 0129 */ 0130 Q_REQUIRED_RESULT inline QString toString(const QStringList &languages) const 0131 { 0132 return this->operator KLocalizedString().toString(languages); 0133 } 0134 0135 /** 0136 * Like toString(), but look for translation in the given domain. 0137 * 0138 * \param domain the translation domain 0139 * \return finalized translation 0140 */ 0141 Q_REQUIRED_RESULT inline QString toString(const char *domain) const 0142 { 0143 return this->operator KLocalizedString().toString(domain); 0144 } 0145 0146 /** 0147 * Like toString(), but resolve KUIT markup into given visual format. 0148 * 0149 * Given visual format overrides that implied by the context UI marker. 0150 * If the message is not markup-aware, this is same as toString(). 0151 * 0152 * \param format the target visual format 0153 * \return finalized translation 0154 */ 0155 Q_REQUIRED_RESULT inline QString toString(Kuit::VisualFormat format) const 0156 { 0157 return this->operator KLocalizedString().toString(format); 0158 } 0159 0160 /** 0161 * Indicate to look for translation only in given languages. 0162 * 0163 * \param languages list of language codes (by decreasing priority) 0164 * \return updated KLocalizedString 0165 */ 0166 Q_REQUIRED_RESULT inline KLocalizedString withLanguages(const QStringList &languages) const 0167 { 0168 return this->operator KLocalizedString().withLanguages(languages); 0169 } 0170 0171 /** 0172 * Indicate to look for translation in the given domain. 0173 * 0174 * \param domain the translation domain 0175 * \return updated KLocalizedString 0176 */ 0177 Q_REQUIRED_RESULT inline KLocalizedString withDomain(const char *domain) const 0178 { 0179 return this->operator KLocalizedString().withDomain(domain); 0180 } 0181 0182 /** 0183 * Indicate to resolve KUIT markup into given visual format. 0184 * 0185 * If the message is not markup-aware, this has no effect. 0186 * 0187 * \param format the target visual format 0188 * \return updated KLocalizedString 0189 */ 0190 Q_REQUIRED_RESULT inline KLocalizedString withFormat(Kuit::VisualFormat format) const 0191 { 0192 return this->operator KLocalizedString().withFormat(format); 0193 } 0194 0195 /** 0196 * Substitute an int argument into the message. 0197 * 0198 * \param a the argument 0199 * \param fieldWidth width of the formatted field, padded by spaces. 0200 * Positive value aligns right, negative aligns left 0201 * \param base the radix used to represent the number as a string. 0202 * Valid values range from 2 to 36 0203 * \param fillChar the character used to fill up the empty places when 0204 * field width is greater than argument width 0205 * \return updated KLocalizedString 0206 */ 0207 Q_REQUIRED_RESULT inline KLocalizedString subs(int a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const 0208 { 0209 return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar); 0210 } 0211 0212 /** 0213 * Substitute an unsigned int argument into the message. 0214 * 0215 * \param a the argument 0216 * \param fieldWidth width of the formatted field, padded by spaces. 0217 * Positive value aligns right, negative aligns left 0218 * \param base the radix used to represent the number as a string. 0219 * Valid values range from 2 to 36 0220 * \param fillChar the character used to fill up the empty places when 0221 * field width is greater than argument width 0222 * \return updated KLocalizedString 0223 */ 0224 Q_REQUIRED_RESULT inline KLocalizedString subs(uint a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const 0225 { 0226 return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar); 0227 } 0228 0229 /** 0230 * Substitute a long argument into the message. 0231 * 0232 * \param a the argument 0233 * \param fieldWidth width of the formatted field, padded by spaces. 0234 * Positive value aligns right, negative aligns left 0235 * \param base the radix used to represent the number as a string. 0236 * Valid values range from 2 to 36 0237 * \param fillChar the character used to fill up the empty places when 0238 * field width is greater than argument width 0239 * \return updated KLocalizedString 0240 */ 0241 Q_REQUIRED_RESULT inline KLocalizedString subs(long a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const 0242 { 0243 return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar); 0244 } 0245 0246 /** 0247 * Substitute an unsigned long argument into the message. 0248 * 0249 * \param a the argument 0250 * \param fieldWidth width of the formatted field, padded by spaces. 0251 * Positive value aligns right, negative aligns left 0252 * \param base the radix used to represent the number as a string. 0253 * Valid values range from 2 to 36 0254 * \param fillChar the character used to fill up the empty places when 0255 * field width is greater than argument width 0256 * \return updated KLocalizedString 0257 */ 0258 Q_REQUIRED_RESULT inline KLocalizedString subs(ulong a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const 0259 { 0260 return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar); 0261 } 0262 0263 /** 0264 * Substitute a long long argument into the message. 0265 * 0266 * \param a the argument 0267 * \param fieldWidth width of the formatted field, padded by spaces. 0268 * Positive value aligns right, negative aligns left 0269 * \param base the radix used to represent the number as a string. 0270 * Valid values range from 2 to 36 0271 * \param fillChar the character used to fill up the empty places when 0272 * field width is greater than argument width 0273 * \return updated KLocalizedString 0274 */ 0275 Q_REQUIRED_RESULT inline KLocalizedString subs(qlonglong a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const 0276 { 0277 return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar); 0278 } 0279 0280 /** 0281 * Substitute an unsigned long long argument into the message. 0282 * 0283 * \param a the argument 0284 * \param fieldWidth width of the formatted field, padded by spaces. 0285 * Positive value aligns right, negative aligns left 0286 * \param base the radix used to represent the number as a string. 0287 * Valid values range from 2 to 36 0288 * \param fillChar the character used to fill up the empty places when 0289 * field width is greater than argument width 0290 * \return updated KLocalizedString 0291 */ 0292 Q_REQUIRED_RESULT inline KLocalizedString subs(qulonglong a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const 0293 { 0294 return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar); 0295 } 0296 /** 0297 * Substitute a double argument into the message. 0298 * 0299 * \param a the argument 0300 * \param fieldWidth width of the formatted field, padded by spaces. 0301 * Positive value aligns right, negative aligns left 0302 * \param format type of floating point formatting, like in QString::arg 0303 * \param precision number of digits after the decimal separator 0304 * \param fillChar the character used to fill up the empty places when 0305 * field width is greater than argument width 0306 * \return updated KLocalizedString 0307 */ 0308 Q_REQUIRED_RESULT inline KLocalizedString subs(double a, int fieldWidth = 0, char format = 'g', int precision = -1, QChar fillChar = QLatin1Char(' ')) const 0309 { 0310 return this->operator KLocalizedString().subs(a, fieldWidth, format, precision, fillChar); 0311 } 0312 0313 /** 0314 * Substitute a \c QChar argument into the message. 0315 * 0316 * \param a the argument 0317 * \param fieldWidth width of the formatted field, padded by spaces. 0318 * Positive value aligns right, negative aligns left 0319 * \param fillChar the character used to fill up the empty places when 0320 * field width is greater than argument width 0321 * \return updated KLocalizedString 0322 */ 0323 Q_REQUIRED_RESULT inline KLocalizedString subs(QChar a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const 0324 { 0325 return this->operator KLocalizedString().subs(a, fieldWidth, fillChar); 0326 } 0327 0328 /** 0329 * Substitute a \c QString argument into the message. 0330 * 0331 * \param a the argument 0332 * \param fieldWidth width of the formatted field, padded by spaces. 0333 * Positive value aligns right, negative aligns left 0334 * \param fillChar the character used to fill up the empty places when 0335 * field width is greater than argument width 0336 * \return updated KLocalizedString 0337 */ 0338 Q_REQUIRED_RESULT inline KLocalizedString subs(const QString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const 0339 { 0340 return this->operator KLocalizedString().subs(a, fieldWidth, fillChar); 0341 } 0342 0343 /** 0344 * Substitute another KLocalizedString into the message. 0345 * 0346 * \param a the argument 0347 * \param fieldWidth width of the formatted field, padded by spaces. 0348 * Positive value aligns right, negative aligns left 0349 * \param fillChar the character used to fill up the empty places when 0350 * field width is greater than argument width 0351 * \return updated KLocalizedString 0352 */ 0353 Q_REQUIRED_RESULT inline KLocalizedString subs(const KLocalizedString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const 0354 { 0355 return this->operator KLocalizedString().subs(a, fieldWidth, fillChar); 0356 } 0357 0358 /** 0359 * Add dynamic context to the message. 0360 * 0361 * See \ref dyn_ctxt for use cases. 0362 * 0363 * \param key context key 0364 * \param value context value 0365 * \return updated KLocalizedString 0366 */ 0367 Q_REQUIRED_RESULT inline KLocalizedString inContext(const QString &key, const QString &value) const 0368 { 0369 return this->operator KLocalizedString().inContext(key, value); 0370 } 0371 0372 /** 0373 * Relax matching between placeholders and arguments. 0374 * 0375 * Normally the placeholders should start from %1 and have no gaps, 0376 * and on finalization there must be exactly as many arguments 0377 * supplied through \c subs methods as there are unique plaecholders. 0378 * If this is not satisfied, in debug mode warnings are printed 0379 * and the finalized string may contain error marks. 0380 * 0381 * This method relaxes the placeholder-argument matching, 0382 * such that there must only be an argument available for 0383 * every present unique placeholder (taking placeholder numbers 0384 * to be 1-based indices into the argument list). 0385 * This can come useful in some situations. 0386 * 0387 * \return updated KLocalizedString 0388 */ 0389 Q_REQUIRED_RESULT inline KLocalizedString relaxSubs() const 0390 { 0391 return this->operator KLocalizedString().relaxSubs(); 0392 } 0393 0394 /** 0395 * Do not resolve KUIT markup. 0396 * 0397 * If the message is markup-aware 0398 * (constructed by one of \c \*xi18n\* calls), 0399 * this function can be used to make it non-markup-aware. 0400 * This may be useful for debugging markup. 0401 * 0402 * \return updated KLocalizedString 0403 */ 0404 Q_REQUIRED_RESULT inline KLocalizedString ignoreMarkup() const 0405 { 0406 return this->operator KLocalizedString().ignoreMarkup(); 0407 } 0408 0409 private: 0410 template<std::size_t TextSize> 0411 friend inline constexpr KLazyLocalizedString kli18n(const char (&text)[TextSize]); 0412 template<std::size_t ContextSize, std::size_t TextSize> 0413 friend constexpr inline KLazyLocalizedString kli18nc(const char (&context)[ContextSize], const char (&text)[TextSize]); 0414 template<std::size_t SingularSize, std::size_t PluralSize> 0415 friend constexpr inline KLazyLocalizedString kli18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize]); 0416 template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize> 0417 friend constexpr inline KLazyLocalizedString 0418 kli18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize]); 0419 template<std::size_t TextSize> 0420 friend constexpr inline KLazyLocalizedString klxi18n(const char (&text)[TextSize]); 0421 template<std::size_t ContextSize, std::size_t TextSize> 0422 friend constexpr inline KLazyLocalizedString klxi18nc(const char (&context)[ContextSize], const char (&text)[TextSize]); 0423 template<std::size_t SingularSize, std::size_t PluralSize> 0424 friend constexpr inline KLazyLocalizedString klxi18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize]); 0425 template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize> 0426 friend constexpr inline KLazyLocalizedString 0427 klxi18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize]); 0428 0429 constexpr inline KLazyLocalizedString(const char *context, const char *text, const char *plural, bool markupAware) 0430 : m_context(context) 0431 , m_text(text) 0432 , m_plural(plural) 0433 , m_markupAware(markupAware) 0434 { 0435 } 0436 0437 const char *m_context = nullptr; 0438 const char *m_text = nullptr; 0439 const char *m_plural = nullptr; 0440 bool m_markupAware = false; 0441 }; 0442 0443 /** 0444 * Mark the string @p text for extraction. 0445 * 0446 * \param text string to translate 0447 * \return KLazyLocalizedString for deferred translation. 0448 * \since 5.89 0449 */ 0450 template<std::size_t TextSize> 0451 constexpr inline KLazyLocalizedString kli18n(const char (&text)[TextSize]) 0452 { 0453 return KLazyLocalizedString(nullptr, text, nullptr, false); 0454 } 0455 0456 /** 0457 * Mark the string @p text with @p context for extraction. 0458 * 0459 * \param context context of the string 0460 * \param text string to translate 0461 * \return KLazyLocalizedString for deferred translation. 0462 * \since 5.89 0463 */ 0464 template<std::size_t ContextSize, std::size_t TextSize> 0465 constexpr inline KLazyLocalizedString kli18nc(const char (&context)[ContextSize], const char (&text)[TextSize]) 0466 { 0467 return KLazyLocalizedString(context, text, nullptr, false); 0468 } 0469 0470 /** 0471 * Mark the string @p singular and @p plural for extraction. 0472 * 0473 * \param singular singular form of the string to translate 0474 * \param plural plural form of the string to translate 0475 * \return KLazyLocalizedString for deferred translation. 0476 * \since 5.89 0477 */ 0478 template<std::size_t SingularSize, std::size_t PluralSize> 0479 constexpr inline KLazyLocalizedString kli18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize]) 0480 { 0481 return KLazyLocalizedString(nullptr, singular, plural, false); 0482 } 0483 0484 /** 0485 * Mark the string @p singular and @p plural with @p context for extraction. 0486 * 0487 * \param context context of the string 0488 * \param singular singular form of the string to translate 0489 * \param plural plural form of the string to translate 0490 * \return KLazyLocalizedString for deferred translation. 0491 * \since 5.89 0492 */ 0493 template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize> 0494 constexpr inline KLazyLocalizedString kli18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize]) 0495 { 0496 return KLazyLocalizedString(context, singular, plural, false); 0497 } 0498 0499 /** 0500 * Mark the markup-aware string @p text for extraction. 0501 * 0502 * \param text string to translate 0503 * \return KLazyLocalizedString for deferred translation. 0504 * \since 5.89 0505 */ 0506 template<std::size_t TextSize> 0507 constexpr inline KLazyLocalizedString klxi18n(const char (&text)[TextSize]) 0508 { 0509 return KLazyLocalizedString(nullptr, text, nullptr, true); 0510 } 0511 0512 /** 0513 * Mark the markup-aware string @p text with @p context for extraction. 0514 * 0515 * \param context context of the string 0516 * \param text string to translate 0517 * \return KLazyLocalizedString for deferred translation. 0518 * \since 5.89 0519 */ 0520 template<std::size_t ContextSize, std::size_t TextSize> 0521 constexpr inline KLazyLocalizedString klxi18nc(const char (&context)[ContextSize], const char (&text)[TextSize]) 0522 { 0523 return KLazyLocalizedString(context, text, nullptr, true); 0524 } 0525 0526 /** 0527 * Mark the markup-aware string @p singular and @p plural for extraction. 0528 * 0529 * \param singular singular form of the string to translate 0530 * \param plural plural form of the string to translate 0531 * \return KLazyLocalizedString for deferred translation. 0532 * \since 5.89 0533 */ 0534 template<std::size_t SingularSize, std::size_t PluralSize> 0535 constexpr inline KLazyLocalizedString klxi18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize]) 0536 { 0537 return KLazyLocalizedString(nullptr, singular, plural, true); 0538 } 0539 0540 /** 0541 * Mark the markup-aware string @p singular and @p plural with @p context for extraction. 0542 * 0543 * \param context context of the string 0544 * \param singular singular form of the string to translate 0545 * \param plural plural form of the string to translate 0546 * \return KLazyLocalizedString for deferred translation. 0547 * \since 5.89 0548 */ 0549 template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize> 0550 constexpr inline KLazyLocalizedString klxi18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize]) 0551 { 0552 return KLazyLocalizedString(context, singular, plural, true); 0553 } 0554 0555 #endif // KLAZYLOCALIZEDSTRING_H