1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example localizedclock-idbased
\ingroup examples-linguist
\examplecategory {User Interface Components}
\meta tags {qtquick,i18n,l10n,linguist,plurals,id-based}
\title Localized Clock with ID-based Translation
\brief The example shows best practices for using Qt's ID-based
translation features in CMake and Qt Quick including the handling
of plurals in different languages, and localized time formats.
\section1 User Interface
The example shows the current time and date in your system's locale and language.
Translation for these languages is supported:
English, German, French, Spanish, Italian, Japanese, Korean, Portuguese,
Arabic, and Chinese.
If your desktop is in another language, it falls back to English.
The example also accepts a locale as a command-line argument to
test different languages and locales without altering your system.:
\c {localizedClockIdBased --locale en_GB} or
\c {localizedClockIdBased --locale de}
By default, the application shows the time and date in the \e{current locale},
but it also provides a button that opens a dialog with a list of time zones.
The user can use the dialog to change the time zone of the clock.
\section2 ID-based Translation
In this example, we use ID-based translation, where translatable
texts are identified by a \e{unique ID} rather than the
traditional \e{context + text} combination
(see \l{Text ID-based translations}). This approach allows
translations to be reused across different contexts.
We demonstrate this by sharing a translation between
\l Main.qml and the \l{Time Zone Dialog}, a QWidget-based
form written in C++.
Another aspect of ID-based translation is that it
separates the text shown in the UI from the developers, making
the source code independent of the actual words presented
to the user.
In the following two screenshots from the application in English,
the two instances of the text "Select time zone: " in the main
window (QML) and the dialog (C++) share the same translation by
using the same ID.
Screenshot from the application window in English version:
\image linguist-localizedclock-idbased_en.webp
The dialog with a list of time zones (English version):
\image linguist-localizedclock-idbased-dialog_en.webp
The main window of the application in German:
\image linguist-localizedclock-idbased_de.webp
The dialog with a list of time zones (German version):
\image linguist-localizedclock-idbased-dialog_de.webp
\section1 Implementation
The application has five parts:
\list
\li \l CMakeLists.txt
\li \l main.cpp
\li \l {Time Zone Dialog}
\li \l {Time Zone Manager}
\li \l Main.qml
\endlist
\section2 CMakeLists.txt
The CMake file of the application enables Qt's ID-based translation
and localization support. Here are the relevant pieces:
\b{\c find_package(Qt6 REQUIRED COMPONENTS Core Linguist Qml Quick):}
Finds and links the required Qt 6 modules, including \c Linguist,
essential for internationalization.
\b{\c qt_standard_project_setup():}
Sets up the internationalization system with support for the listed
locales. Although the source language is English, an English
translation is still required when using ID-based
translation. The source code only contains the IDs and does not see
the source texts. Hence, we need to set up the project with the
English translation, so that qt_add_translations creates a TS
file for English; otherwise, they will be missing at runtime.
\quotefromfile localizedclock-idbased/CMakeLists.txt
\skipto qt_standard_project_setup
\printuntil I18N_TRANSLATED_LANGUAGES
\b{\c qt_add_translations(...):}
Bundles the functionality of \c lupdate and \c lrelease by generating the
translation source files (TS files) in the "i18n" directory using
\c clock as the base name, and compiling them into binary \c .qm files if
they contain translations.
\list
\li Generates one TS file per language
listed in \c I18N_TRANSLATED_LANGUAGES of \c qt_standard_project_setup.
\li \c MERGE_QT_TRANSLATIONS and \c {QT_TRANSLATION_CATALOGS qtbase} include
the Qt translations in the project. This is necessary to translate
the buttons of the \c QDialog widget in the \l{Time Zone Dialog}. As the text
on those buttons is controlled by QDialog, without including Qt
translations those buttons do not get translated (see the translated
texts of the dialog in the German screenshots in \l {ID-based Translation}).
\endlist
\quotefromfile localizedclock-idbased/CMakeLists.txt
\skipto qt_add_translations
\printuntil )
\b{\c qt_add_qml_module(...):}
Adds a QML module under the URI \c qtexamples.localizedclock,
includes the \l Main.qml file, and imports the source and header
files of \l{Time Zone Manager} into the QML module.
\quotefromfile localizedclock-idbased/CMakeLists.txt
\skipto qt_add_qml_module
\printuntil )
\section2 main.cpp
The starting point of the application. This part is responsible
for setting the locale, installing required translations, and
loading UI. Below is an explanation of the relevant pieces of code:
Define the locale argument, e.g., \c {--locale en_US} or \c{--locale de_DE}:
\quotefromfile localizedclock-idbased/main.cpp
\skipto QCommandLineParser parser
\printuntil parser.process
Parse the arguments, fetch the provided locale, and set the input
locale as the default locale of the application:
\quotefromfile localizedclock-idbased/main.cpp
\skipto QLocale locale
\printuntil QLocale::setDefault
Install the English translation regardless of the locale, to allow incomplete
translations for other languages. QTranslator queries translations
for texts in the reversed order in which the translations are installed:
\quotefromfile localizedclock-idbased/main.cpp
\skipto QTranslator enPlurals
\printuntil app.installTranslator
Install a translation according to the given locale:
\quotefromfile localizedclock-idbased/main.cpp
\skipto QTranslator translation
\printuntil }
\printuntil }
\printuntil }
As we installed English translation in the previous step, we might end
up with two installed translations. Qt uses the most recently installed
translation for any overlapping keys. Therefore, the locale-specific
translation will take precedence over English, and in case of any missing
translations, QTranslator falls back to English.
\section2 Time Zone Dialog
This class is a C++ \l {QWidget}-based dialog (\l QDialog) that shows a
\l QComboBox containing a list of time zones.
Below is an explanation of the code:
Enable ID-based translation in the UI form (dialog.ui):
\code
<ui version="4.0" idbasedtr="true">
\endcode
Set the title with ID-based translation (dialog.ui). Here,
"title" is the unique ID of the translation:
\code
<property name="windowTitle">
<string id="title">Time Zone</string>
</property>
\endcode
Add a label with ID-based translation (dialog.ui), with the
ID "timezonelabel":
\code
<widget class="QLabel" name="label">
...
<property name="text">
<string id="timezonelabel">Select time zone</string>
</property>
...
</widget>
\endcode
\section2 Time Zone Manager
A \c QML_SINGLETON class in \c C++ responsible for handling
time zone changes.
Upon selecting a time zone by the user, the instance of \c TimeZoneManager
remembers the chosen time zone:
\quotefromfile localizedclock-idbased/timezonemanager.cpp
\skipto connect
\printuntil connect
Updating the time zone emits a TimeZoneManager::timeZoneChanged signal:
\quotefromfile localizedclock-idbased/timezonemanager.cpp
\skipto TimeZoneManager::setTimeZone
\printuntil }
\printuntil }
\c TimeZoneManager::currentTimeZoneOffsetMs() is marked with
\l Q_INVOKABLE and returns the time offset of the selected time zone.
Since the \c TimeZoneManager class is declared with \l QML_ELEMENT
and \l QML_SINGLETON, the method can be directly accessed from QML
to update the presented time; also, see \l{Main.qml}.
\quotefromfile localizedclock-idbased/timezonemanager.cpp
\skipto currentTimeZoneOffsetMs
\printuntil }
\section2 Main.qml
The main QML file defines the application's user interface.
The UI presents time, date, current time zone, and a counter for seconds.
It also provides a button that opens a \l {Time Zone Dialog} to change the
time zone.
Below is an explanation of the relevant pieces of code:
\b{Define the window and set its title using \l{Qt::}{qsTrId()}
for ID-based translation.} The text
for the source language is specified using the meta string
notation \c {//%} (see \l {Text ID-based translations}).
\l lupdate parses the
meta strings and writes the defined source texts to the TS file.
As the source text is specified using meta strings and in the form
of a comment, they are not visible to the application at runtime.
Hence, when the application is loaded in the English locale, even
though the source language is in English, it still needs to install
the English translation to present the English texts.
Otherwise, the raw ID "Main-Digital-Clock" is shown. This is also
why we specified "en" in \c I18N_TRANSLATED_LANGUAGES
by the setup in \l{CMakeLists.txt}.
\qml
//% "Digital Clock"
title: qsTrId("Main-Digital-Clock")
\endqml
\b{Show the number of seconds using \l{Qt::}{qsTrId()} with plural
support.} Again here the text in the source language is specified using
the \c{//%} meta string.
The plural form is enabled by using the special notation "%n"
in the source text in the meta string (see \l{Handle Plural Forms}).
Depending on the value of n, the translation function returns a
different translation, with the correct grammatical number for the
target language.
For instance in English, if the value of \c root.seconds is larger
than one, the plural form is used, otherwise the singular form is used.
In \l{Translation Rules for Plural Forms} you find the plural rules
for different languages.
\qml
//% "%n second(s)"
text: qsTrId("Main-n-second-s", root.seconds)
\endqml
\b{Display the currently selected time zone using ID-based
translation,} with \c { //% "Time zone: "} specifying the
text in the source language:
\qml
//% "Time zone: "
text: qsTrId("timezone") + TimeZoneManager.timeZone;
\endqml
\b{A Button to open the \l{Time Zone Dialog}.} The text on the
button is specified using \l{Qt::}{qsTrId()} for ID-based
translation. In this case, the source text is not defined by meta
strings anymore since this is a reuse of the ID "timezonelabel",
which was previously used in the dialog.ui document
(see \l{Time Zone Dialog}). In ID-based translation, it
suffices to specify the source text per ID only once in the project:
\quotefromfile localizedclock-idbased/Main.qml
\skipto Button
\printuntil }
Upon changing the time zone and receiving the
\c TimeZoneManager::timeZoneChanged() signal
(see \l{Time Zone Manager}), update the \c diff variable with
the time offset of the selected time zone:
\quotefromfile localizedclock-idbased/Main.qml
\skipto Connections
\printuntil }
\printuntil }
\b{Declare a Timer} that triggers every second and updates the time,
date, and seconds properties. The timer calculates the time by adding the
current time to the time offset of the selected time zone:
\quotefromfile localizedclock-idbased/Main.qml
\skipto Timer
\printuntil }
\printuntil }
The locale affects how dates and times are displayed.
These are formatted according to the current locale's country conventions.
For example, a German locale results in 24-hour time and
\e DD.MM.YYYY date format, while a US locale uses a 12-hour clock and
\e MM/DD/YYYY date format.
*/
|