KI18n

klocalization.h
1/*
2 SPDX-FileCopyrightText: 2024 Lukas Sommer <sommerluk@gmail.com>
3 SPDX-FileCopyrightText: 2024 Volker Krause <vkrause@kde.org>
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#ifndef KLOCALIZATION_H
8#define KLOCALIZATION_H
9
10#include "klocalizedstring.h"
11
12#include <QObject>
13
14#include <type_traits>
15
16class QDoubleSpinBox;
17class QSpinBox;
18
19/**
20 * @namespace KLocalization
21 * @brief Namespace containing helpers for localization.
22 * @since 6.5
23 */
24namespace KLocalization
25{
26
27///@cond hidden
28namespace Private
29{
30
31constexpr inline const char SpinBoxFormatStringProperty[] = "__KLocalizationFormatStringPrivate";
32
33}
34///@endcond
35
36/**
37 * @brief Retranslates a previously set up format string to the current
38 * language and updates the spin box.
39 *
40 * The format string is initially set up by setupSpinBoxFormatString().
41 * This function updates the prefix and suffix of a spin box to reflect the
42 * current language settings. It is useful for responding to language changes,
43 * such as those triggered by QEvent::LanguageChange.
44 *
45 * @tparam T The type of the spin box, which must be either QSpinBox or
46 * QDoubleSpinBox.
47 * @param spinBox Pointer to the spin box.
48 *
49 * @post The prefix and suffix of the spin box are updated to reflect the
50 * current language.
51 *
52 * @sa @ref setupSpinBoxFormatString
53 *
54 * @since 6.5
55 */
56
57template<typename T>
58inline void retranslateSpinBoxFormatString(T *spinBox)
59{
60 constexpr bool isSpinBox = std::is_base_of_v<QSpinBox, T> || std::is_base_of_v<QDoubleSpinBox, T>;
61 static_assert(isSpinBox, "First argument must be a QSpinBox or QDoubleSpinBox.");
62
63 const auto lString = spinBox->property(Private::SpinBoxFormatStringProperty).template value<KLocalizedString>();
64 // The KLocalizedString::subs() method performs two tasks:
65 // 1. It replaces placeholders (%1, %2, ...) in the string with actual
66 // content.
67 // 2. If the argument is an integer, it selects the appropriate plural form
68 // based on the value.
69 // In this context, the string is expected not to contain any standard
70 // placeholders (%1, %2, ...). Instead, it should contain a custom
71 // placeholder (%v) which is ignored by KLocalizedString::subs().
72 // The only purpose of calling KLocalizedString::subs() here is to ensure
73 // the correct plural form is used when spinBox->value() is an integer.
74 // If spinBox->value() is a double, KLocalizedString::subs() does not
75 // perform any operations on the string since plural handling applies only
76 // to integer values.
77 const auto translation = lString.subs(spinBox->value()).toString();
78 const auto parts = translation.split(QLatin1StringView("%v"));
79 if (parts.count() == 2) {
80 spinBox->setPrefix(parts.at(0));
81 spinBox->setSuffix(parts.at(1));
82 } else {
83 spinBox->setPrefix(QString());
84 spinBox->setSuffix(QString());
85 }
86}
87
88/**
89 * @brief Sets up a format string for internationalizing spin boxes.
90 *
91 * This function allows the customization of prefix and suffix for spin boxes
92 * (QSpinBox and QDoubleSpinBox), considering internationalization needs.
93 *
94 * Spin boxes display a number and possibly a prefix and/or suffix. However,
95 * in some languages, the position of the prefix and suffix may be reversed
96 * compared to English. Example: In English, you write 50%, but in Turkish,
97 * you write %50. Qt does not offer an out-of-the-box solution for this. This
98 * helper now provides complete internationalization for prefixes and suffixes
99 * of spin boxes.
100 *
101 * For QSpinBox it also provides correct plural handling by installing a
102 * handler for the valueChanged() signal to update prefix and suffix whenever
103 * the spin box value changes in the future.
104 *
105 * Example usage:
106 * @code
107 * QDoubleSpinBox doubleBox;
108 * KLocalization::setupSpinBoxFormatString(
109 * &doubleBox,
110 * ki18nc("@item %v is a number and the second % is the percent sign", "%v%"));
111 * // Turkish translation: "%%v"
112 *
113 * QSpinBox intBox;
114 * KLocalization::setupSpinBoxFormatString(
115 * &intBox,
116 * ki18ncp("@item %v is a number", "Baking %v cake", "Baking %v cakes"));
117 * @endcode
118 *
119 * @tparam T The type of the spin box, which must be either QSpinBox or QDoubleSpinBox.
120 * @param spinBox Pointer to the spin box.
121 * @param formatString A localized string in the format "PREFIX%vSUFFIX".
122 * - For QDoubleSpinBox, plural forms in @p formatString are ignored
123 * and should be avoided. Use @ref KLocalizedString::ki18nc "ki18nc()"
124 * to generate the format string.
125 * - For QSpinBox, if @p formatString includes plural forms, they are
126 * utilized. While optional, their use is highly recommended for
127 * accurate pluralization. Use @ref KLocalizedString::ki18ncp "ki18ncp()"
128 * to generate the format string.
129 *
130 * @note It is safe to call this function multiple times on the same spin box.
131 *
132 * @sa @ref retranslateSpinBoxFormatString
133 *
134 * @since 6.5
135 */
136
137template<typename T>
138inline void setupSpinBoxFormatString(T *spinBox, const KLocalizedString &formatString)
139{
140 constexpr bool isSpinBox = std::is_base_of_v<QSpinBox, T>;
141 constexpr bool isDoubleSpinBox = std::is_base_of_v<QDoubleSpinBox, T>;
142 static_assert(isSpinBox || isDoubleSpinBox, "First argument must be a QSpinBox or QDoubleSpinBox.");
143
144 if constexpr (isSpinBox) {
145 const bool hasSetup = !spinBox->property(Private::SpinBoxFormatStringProperty).isNull();
146 if (!hasSetup) {
147 QObject::connect(spinBox, &T::valueChanged, spinBox, [spinBox]() {
149 });
150 }
151 }
152 // Using relaxSubs() to avoid error marks if the library user did pass
153 // a singular-only KLocalizedString.
154 spinBox->setProperty(Private::SpinBoxFormatStringProperty, QVariant::fromValue(formatString.relaxSubs()));
156}
157
158}
159
160#endif
Class for producing and handling localized messages.
KLocalizedString relaxSubs() const
Relax matching between placeholders and arguments.
Namespace containing helpers for localization.
void retranslateSpinBoxFormatString(T *spinBox)
Retranslates a previously set up format string to the current language and updates the spin box.
void setupSpinBoxFormatString(T *spinBox, const KLocalizedString &formatString)
Sets up a format string for internationalizing spin boxes.
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:10:09 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.