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

KDE's Doxygen guidelines are available online.