source: trunk/tools/linguist/book/linguist-programmer.leaf@ 193

Last change on this file since 193 was 193, checked in by rudi, 14 years ago

Qt Linguist added

File size: 37.1 KB
Line 
1\chapter Programmers
2
3Support for multiple languages is extremely simple in Qt
4applications, and adds little overhead to the programmer's workload.
5
6Qt minimizes the performance cost of using translations by
7translating the phrases for each window as they are created. In most
8applications the main window is created just once. Dialogs are often
9created once and then shown and hidden as required. Once the initial
10translation has taken place there is no further runtime overhead for
11the translated windows. Only those windows that are created,
12destroyed and subsequently created will have a translation
13performance cost.
14
15Creating applications that can switch language at runtime is possible
16with Qt, but requires a certain amount of programmer intervention and
17will of course incur some runtime performance cost.
18
19\section1 Making the Application Translation Aware
20
21Programmers should make their application look for and load the
22appropriate translation file and mark user-visible text and Ctrl
23keyboard accelerators as targets for translation.
24
25Each piece of text that requires translating requires context to help
26the translator identify where in the program the text occurs. In the
27case of multiple identical texts that require different translations,
28the translator also requires some information to disambiguate the
29source texts. Marking text for translation will automatically cause
30the class name to be used as basic context information. In some cases
31the programmer may be required to add additional information to help
32the translator.
33
34\section2 Creating Translation Files
35
36\index .ts Files
37\index Translation Source Files
38
39Translation files consist of all the user-visible text and Ctrl key
40accelerators in an application and translations of that text.
41Translation files are created as follows:
42
43\index lupdate
44\index lrelease
45
46\list 1
47\i Run \l lupdate initially to generate the first set of \c .ts
48translation source files with all the user-visible text but no
49translations.
50\i The \c .ts files are given to the translator who adds translations
51using \e {Qt Linguist}. \e {Qt Linguist} takes care of any changed
52or deleted source text.
53\i Run \l lupdate to incorporate any new text added to the
54application. \l lupdate synchronizes the user-visible text from the
55application with the translations; it does not destroy any data.
56\i Steps 2 and 3 are repeated as often as necessary.
57\i When a release of the application is needed \l lrelease is run to
58read the \c .ts files and produce the \c .qm files used by the
59application at runtime.
60\endlist
61
62\index .pro Files
63\index Project Files
64\index qmake!Project Files
65
66For \l lupdate to work successfully, it must know which translation
67files to produce. The files are simply listed in the application's \c
68.pro Qt project file, for example:
69\quotefile tt2/tt2.pro
70\skipto TRANSLATIONS
71\printline TRANSLATIONS
72\printline
73
74See the \link lupdate "lupdate" \endlink and \link lrelease
75"lrelease" \endlink sections.
76
77\section2 Loading Translations
78
79\quotefile tt1/main.cpp
80\skipto main(
81\printline main(
82\printuntil QApplication
83
84\index main()
85
86This is how a simple \c main() function of a Qt application begins.
87
88\index QTranslator!load()
89\index load()!QTranslator
90\index QApplication!installTranslator()
91\index installTranslator()!QApplication
92
93\quotefile tt1/main.cpp
94\skipto main(
95\printline main(
96\printuntil app.installTrans
97
98For a translation-aware application a translator object is created, a
99translation is loaded and the translator object installed into the
100application.
101
102\quotefile tt2/main.cpp
103\skipto main(
104\printline main(
105\printuntil app.installTrans
106
107In production applications a more flexible approach, for example,
108loading translations according to locale, might be more appropriate. If
109the \c .ts files are all named according to a convention such as
110\e appname_locale, e.g. \c tt2_fr, \c tt2_de etc, then the
111code above will load the current locale's translation at runtime.
112
113If there is no translation file for the current locale the application
114will fall back to using the original source text.
115
116\section2 Making the Application Translate User-Visible Strings
117
118\index tr()
119\index QObject!tr()
120
121User-visible strings are marked as translation targets by wrapping them
122in a \c tr() call, for example:
123\code
124 button = new QPushButton( "&Quit", this );
125\endcode
126
127would become
128
129\code
130 button = new QPushButton( tr("&Quit"), this);
131\endcode
132
133\index Q_OBJECT
134
135All \l QObject subclasses that use the \c Q_OBJECT macro implement
136the \c tr() function.
137
138Although the \c tr() call is normally made directly since it is
139usually called as a member function of a \l QObject subclass, in
140other cases an explicit class name can be supplied, for example:
141
142\code
143 QPushButton::tr("&Quit")
144\endcode
145
146or
147
148\code
149 QObject::tr("&Quit")
150\endcode
151
152\section2 Distinguishing Identical Strings That Require Different
153Translations
154
155\index Translation Contexts
156\index Contexts!for Translation
157\index lupdate
158
159The \l lupdate program automatically provides a \e context for every
160source text. This context is the class name of the class that contains
161the \c tr() call. This is sufficient in the vast majority of cases.
162Sometimes however, the translator will need further information to
163uniquely identify a source text; for example, a dialog that contained
164two separate frames, each of which contained an "Enabled" option would
165need each identified because in some languages the translation would
166differ between the two. This is easily achieved using the
167two argument form of the \c tr() call, e.g.
168
169\code
170 rbc = new QRadioButton( tr("Enabled", "Color frame"), this );
171\endcode
172
173and
174
175\code
176 rbh = new QRadioButton( tr("Enabled", "Hue frame"), this );
177\endcode
178
179\index Ctrl Key
180
181Ctrl key accelerators are also translatable:
182
183\quotefile tt3/mainwindow.cpp
184\skipto quit()
185\printline quit()
186\printuntil Quit
187
188It is strongly recommended that the two argument form of \c tr() is used
189for Ctrl key accelerators. The second argument is the only clue the
190translator has as to the function performed by the accelerator.
191
192\section2 Helping The Translator With Navigation Information
193
194\index TRANSLATOR!in Comments
195\index Translator Comments
196\index Comments!for Translators
197
198In large complex applications it may be difficult for the translator to
199see where a particular source text comes from. This problem can be
200solved by adding a comment using the keyword \e TRANSLATOR which
201describes the navigation steps to reach the text in question; e.g.
202
203\code
204 /* TRANSLATOR FindDialog
205
206 Choose Edit|Find from the menu bar or press Ctrl+F to pop up the
207 Find dialog.
208 */
209\endcode
210
211These comments are particularly useful for widget classes.
212
213\section2 Coping With C++ Namespaces
214
215\index Namespaces
216\index C++!Namespaces
217\index lupdate
218
219C++ namespaces and the \c {using namespace} statement can confuse
220\l lupdate. It will interpret \c MyClass::tr() as meaning just
221that, not as \c MyNamespace::MyClass::tr(), even if \c MyClass is
222defined in the \c MyNamespace namespace. Runtime translation of
223these strings will fail because of that.
224
225\index TRANSLATOR!in Comments
226\index Translator Comments
227\index Comments!for Translators
228
229You can work around this limitation by putting a \e TRANSLATOR
230comment at the beginning of the source files that use \c
231MyClass::tr():
232\code
233 /* TRANSLATOR MyNamespace::MyClass */
234\endcode
235After the comment, all references to \c MyClass::tr() will be
236understood as meaning \c MyNamespace::MyClass::tr().
237
238\section2 Translating Text that is Outside of a QObject subclass
239
240\section3 Using QApplication::translate()
241
242If the quoted text is not in a member function of a QObject subclass,
243use either the tr() function of an appropriate class, or the
244QApplication::translate() function directly:
245
246\code
247 void some_global_function( LoginWidget *logwid )
248 {
249 QLabel *label = new QLabel(
250 LoginWidget::tr("Password:"), logwid );
251 }
252
253 void same_global_function( LoginWidget *logwid )
254 {
255 QLabel *label = new QLabel(
256 qApp->translate("LoginWidget", "Password:"),
257 logwid );
258 }
259\endcode
260
261\section3 Using QT_TR_NOOP() and QT_TRANSLATE_NOOP()
262
263If you need to have translatable text completely outside a function,
264there are two macros to help: QT_TR_NOOP() and QT_TRANSLATE_NOOP().
265These macros merely mark the text for extraction by \l{lupdate}.
266The macros expand to just the text (without the context).
267
268Example of QT_TR_NOOP():
269\code
270 QString FriendlyConversation::greeting( int greet_type )
271 {
272 static const char* greeting_strings[] = {
273 QT_TR_NOOP( "Hello" ),
274 QT_TR_NOOP( "Goodbye" )
275 };
276 return tr( greeting_strings[greet_type] );
277 }
278\endcode
279
280Example of QT_TRANSLATE_NOOP():
281\code
282 static const char* greeting_strings[] = {
283 QT_TRANSLATE_NOOP( "FriendlyConversation", "Hello" ),
284 QT_TRANSLATE_NOOP( "FriendlyConversation", "Goodbye" )
285 };
286
287 QString FriendlyConversation::greeting( int greet_type )
288 {
289 return tr( greeting_strings[greet_type] );
290 }
291
292 QString global_greeting( int greet_type )
293 {
294 return qApp->translate( "FriendlyConversation",
295 greeting_strings[greet_type] );
296 }
297\endcode
298
299\section1 Tutorials
300
301Three tutorials are presented. The first demonstrates the creation of
302a \l QTranslator object. It also shows the simplest use of the \c
303tr() function to mark user-visible source text for translation. The
304second tutorial explains how to make the application load the
305translation file applicable to the current locale. It also shows the
306use of the two-argument form of \c tr() which provides additional
307information to the translator. The third tutorial explains how
308identical source texts can be distinguished even when they occur in
309the same context. This tutorial also discusses how the translation
310tools help minimize the translator's work when an application is
311upgraded.
312
313\section2 Tutorial 1: Loading and Using Translations
314
315\img tt1_en.png
316\caption Tutorial 1 Screenshot, English version
317
318\include tt1/tt1.pro
319\caption \c tt1.pro
320
321\include tt1/main.cpp
322\caption \c main.cpp
323
324This example is a reworking of the \link tutorial1-01.html
325"hello-world" \endlink example from \link tutorial.html Tutorial
326#1\endlink, with a Latin translation. The \e {Tutorial 1 Screenshot,
327English version}, above, shows the English version.
328
329\quotefile tt1/main.cpp
330
331\section3 Line by Line Walk-through
332
333\quotefile tt1/main.cpp
334
335\skipto qtranslator
336\printline qtranslator
337
338\index QTranslator
339
340This line includes the definition of the \l QTranslator class.
341Objects of this class provide translations for user-visible text.
342
343\skipto QTranslator
344\printuntil tor
345
346Creates a \l QTranslator object without a parent.
347
348\printline load
349
350\index tt1_la.qm
351
352Tries to load a file called \c tt1_la.qm (the \c .qm file extension is
353implicit) that contains Latin translations for the source texts used in
354the program. No error will occur if the file is not found.
355
356\index QApplication!installTranslator()
357\index installTranslator()!QApplication
358
359\printline installTranslator
360
361Adds the translations from \c tt1_la.qm to the pool of translations used
362by the program.
363
364\index Hello World
365
366\printline hello
367
368Creates a push button that displays "Hello world!". If \c tt1_la.qm
369was found and contains a translation for "Hello world!", the
370translation appears; if not, the source text appears.
371
372\index tr()
373\index QObject!tr()
374
375All classes that inherit \l QObject have a \c tr() function. Inside
376a member function of a \l QObject class, we simply write \c tr("Hello
377world!") instead of \c QPushButton::tr("Hello world!") or \c
378QObject::tr("Hello world!").
379
380\section3 Running the Application in English
381
382\index English Language
383
384Since we haven't made the translation file \c tt1_la.qm, the source text
385is shown when we run the application:
386
387\img tt1_en.png
388\caption Tutorial 1 Screenshot, English version
389
390\section3 Creating a Latin Message File
391
392\index tt1.pro
393\index Latin
394
395The first step is to create a project file, \c tt1.pro, that lists
396all the source files for the project. The project file can be a qmake
397project file, or even an ordinary makefile. Any file that contains
398
399\index SOURCES!in Project Files
400\index TRANSLATIONS!in Project Files
401
402\quotefile tt1/tt1.pro
403\skipto SOURCES
404\printline SOURCES
405\skipto TRANSLATIONS
406\printline TRANSLATIONS
407
408will work. \e TRANSLATIONS specifies the message files we want to
409maintain. In this example, we just maintain one set of translations,
410namely Latin.
411
412\index .ts Files
413\index Translation Source Files
414\index .qm Files
415\index Qt Message Files
416
417Note that the file extension is \c .ts, not \c .qm. The \c .ts
418translation source format is designed for use during the
419application's development. Programmers or release managers run the \l
420lupdate program to generate and update \c .ts files with the source
421text that is extracted from the source code. Translators read and
422update the \c .ts files using \e {Qt Linguist} adding and editing
423their translations.
424
425\index XML
426
427The \c .ts format is human-readable XML that can be emailed directly
428and is easy to put under version control. If you edit this file
429manually, be aware that the default encoding for XML is UTF-8, not
430Latin-1 (ISO 8859-1). One way to type in a Latin-1 character such as
431'\OSLASH' (Norwegian o with slash) is to use an XML entity:
432"\ø". This will work for any Unicode character.
433
434Once the translations are complete the \l lrelease program is used to
435convert the \c .ts files into the \c .qm Qt message file format. The
436\c .qm format is a compact binary format designed to deliver very
437fast lookup performance. Both \l lupdate and \l lrelease read all the
438project's source and header files (as specified in the HEADERS and
439SOURCES lines of the project file) and extract the strings that
440appear in \c tr() function calls.
441
442\index lupdate
443
444\l lupdate is used to create and update the message files (\c tt1_la.ts
445in this case) to keep them in sync with the source code. It is safe to
446run \l lupdate at any time, as \l lupdate does not remove any
447information. For example, you can put it in the makefile, so the \c .ts
448files are updated whenever the source changes.
449
450\index .ts Files
451\index Translation Source Files
452\index XML
453
454Try running \l lupdate right now, like this:
455\code
456 lupdate -verbose tt1.pro
457\endcode
458(The \c -verbose option instructs \c lupdate to display messages that
459explain what it is doing.) You should now have a file \c tt1_la.ts in
460the current directory, containing this:
461\code
462 <!DOCTYPE TS><TS>
463 <context>
464 <name>QPushButton</name>
465 <message>
466 <source>Hello world!</source>
467 <translation type="unfinished"></translation>
468 </message>
469 </context>
470 </TS>
471\endcode
472You don't need to understand the file format since it is read and
473updated using tools (\l lupdate, \e {Qt Linguist}, \l lrelease).
474
475\section3 Translating to Latin with Qt Linguist
476
477\index Qt Linguist
478\index Linguist
479
480We will use \e {Qt Linguist} to provide the translation, although
481you can use any XML or plain text editor to enter a translation into a
482\c .ts file.
483
484To start \e {Qt Linguist}, type
485\code
486 linguist tt1_la.ts
487\endcode
488
489You should now see the text "QPushButton" in the top left pane.
490Double-click it, then click on "Hello world!" and enter "Orbis, te
491saluto!" in the \e Translation pane (the middle right of the
492window). Don't forget the exclamation mark!
493
494Click the \e Done checkbox and choose \e File|Save from the
495menu bar. The \c .ts file will no longer contain
496\code
497 <translation type='unfinished'></translation>
498\endcode
499but instead will have
500\code
501 <translation>Orbis, te saluto!</translation>
502\endcode
503
504\section3 Running the Application in Latin
505
506\index Latin
507\index lrelease
508
509To see the application running in Latin, we have to generate a \c .qm
510file from the \c .ts file. Generating a \c .qm file can be achieved
511either from within \e {Qt Linguist} (for a single \c .ts file), or
512by using the command line program \l lrelease which will produce one \c
513.qm file for each of the \c .ts files listed in the project file.
514Generate \c tt1_la.qm from \c tt1_la.ts by choosing
515\e File|Release from \e {Qt Linguist}'s menu bar and pressing
516\e Save in the file save dialog that pops up. Now run the \e tt1 example
517program again. This time the button will be labelled "Orbis, te
518saluto!".
519
520\img tt1_la.png
521\caption Tutorial 1 Screenshot, Latin version
522
523\section2 Tutorial 2: Using Two or More Languages
524
525\img tt2_en.png
526\caption Tutorial 2 Screenshot, English version
527
528\index .pro Files
529\index Project Files
530\index qmake!Project Files
531
532\include tt2/tt2.pro
533\caption tt2.pro
534
535\index Translation Contexts
536\index Contexts!for Translation
537
538This example is a slightly more involved and introduces a key
539\e {Qt Linguist} concept: "contexts".
540
541\list
542\i \c arrowpad.h contains the definition of \c ArrowPad, a custom widget;
543\i \c arrowpad.cpp contains the implementation of \c ArrowPad;
544\i \c mainwindow.h contains the definition of \c MainWindow, a subclass of
545 \l QMainWindow
546\i \c mainwindow.cpp contains the implementation of \c MainWindow;
547\i \c main.cpp contains main().
548\endlist
549
550\index tt2.pro
551\index French Language
552\index Dutch Language
553
554We will use two translations, French and Dutch, although there is no
555effective limit on the number of possible translations that can be used
556with an application. The relevant lines of \c tt2.pro are
557
558\quotefile tt2/tt2.pro
559\skipto HEADERS
560\printuntil tt2_nl.ts
561
562\index lupdate
563\index tt2_fr.ts
564\index tt2_nl.ts
565
566Run \l lupdate; it should produce two identical message files
567\c tt2_fr.ts and \c tt2_nl.ts. These files will contain all the source
568texts marked for translation with \c tr() calls and their contexts.
569
570\section3 Line by Line Walk-through
571
572\index ArrowPad!in Translation Tutorial
573\index English Language
574
575In \c arrowpad.h we define the \c ArrowPad subclass which is a
576subclass of \l QWidget. In the \e {Tutorial 2 Screenshot, English
577version}, above, the central widget with the four buttons is an
578\c ArrowPad.
579
580\quotefile tt2/arrowpad.h
581\skipto class ArrowPad
582\printline class ArrowPad
583
584\index Q_OBJECT
585\index tr()
586\index QObject!tr()
587\index Translation Contexts
588\index Contexts!for Translation
589
590When \l lupdate is run it not only extracts the source texts but it
591also groups them into contexts. A context is the name of the class in
592which the source text appears. Thus, in this example, "ArrowPad" is a
593context: it is the context of the texts in the \c ArrowPad class.
594The \c Q_OBJECT macro defines \c tr(x) in \c ArrowPad like this
595
596\index QApplication!translate()
597\index translate()!QApplication
598
599\code
600 qApp->translate( "ArrowPad", x )
601\endcode
602
603Knowing which class each source text appears in enables \e {Qt
604Linguist} to group texts that are logically related together, e.g.
605all the text in a dialog will have the context of the dialog's class
606name and will be shown together. This provides useful information for
607the translator since the context in which text appears may influence how
608it should be translated. For some translations keyboard
609accelerators may need to be changed and having all the source texts in a
610particular context (class) grouped together makes it easier for the
611translator to perform any accelerator changes without introducing
612conflicts.
613
614In \c arrowpad.cpp we implement the \c ArrowPad class.
615
616\quotefile tt2/arrowpad.cpp
617\skipto QPushButton
618\printline QPushButton
619
620We call \c ArrowPad::tr() for each button's label since the labels are
621user-visible text.
622
623\img tt2_en.png
624\caption Tutorial 2 Screenshot, English version
625
626\index Q_OBJECT
627\index MainWindow!in Translation Tutorial
628
629\quotefile tt2/mainwindow.h
630\skipto QMainWindow
631\printline QMainWindow
632\printuntil Q_OBJECT
633
634In the \e {Tutorial 2 Screenshot, English version}, above, the whole
635window is a \c MainWindow. This is defined in the \c mainwindow.h
636header file. Here too, we use \c Q_OBJECT, so that \c MainWindow will
637become a context in \e {Qt Linguist}.
638
639In the implementation of \c MainWindow, \c mainwindow.cpp, we create
640an instance of our \c ArrowPad class
641
642\quotefile tt2/mainwindow.cpp
643\skipto arrow pad
644\printline arrow pad
645
646We also call \c MainWindow::tr() twice, once for the menu item and
647once for the accelerator.
648
649\index Ctrl Key
650\index Alt Key
651
652\skipto quit()
653\printline quit()
654\printuntil Ctrl+Q
655
656Note the use of \c tr() to support different keys in other languages.
657"Ctrl+Q" is a good choice for Quit in English, but a Dutch translator
658might want to use "Ctrl+A" (for Afsluiten) and a German translator
659"Strg+E" (for Beenden). When using \c tr() for Ctrl key accelerators,
660the two argument form should be used with the second argument
661describing the function that the accelerator performs.
662
663\index main()
664
665Our \c main() function is defined in \c main.cpp as usual.
666
667\quotefile tt2/main.cpp
668\skipto QTranslator
669\printline QTranslator
670\printuntil install
671
672\index QTextCodec!locale()
673\index locale()!QTextCodec
674\index LANG!Environment Variable
675\index Environment Variables!LANG
676
677We choose which translation to use according to the current locale.
678\l QTextCodec::locale() can be influenced by setting the \c LANG
679environment variable, for example. Notice that the use of a naming
680convention that incorporates the locale for \c .qm message files,
681(and \c .ts files), makes it easy to implement choosing the
682translation file according to locale.
683
684If there is no \c .qm message file for the locale chosen the original
685source text will be used and no error raised.
686
687\section3 Translating to French and Dutch
688
689We'll begin by translating the example application into French. Start
690\e {Qt Linguist} with \c tt2_fr.ts. You should get the seven source
691texts ("\&Up", "\&Left", etc.) grouped in two contexts ("ArrowPad"
692and "MainWindow").
693
694Now, enter the following translations:
695
696\list
697\i \c ArrowPad
698 \list
699 \i \&Up - \&Haut
700 \i \&Left - \&Gauche
701 \i \&Right - \&Droite
702 \i \&Down - \&Bas
703 \endlist
704\i \c MainWindow
705 \list
706 \i E\&xit - \&Quitter
707 \i Ctrl+Q - Ctrl+Q
708 \i \&File - \&Fichier
709 \endlist
710\endlist
711
712It's quickest to press \Key Alt+D (which clicks the \e {Done \& Next}
713button) after typing each translation, since this marks the
714translation as done and moves on to the next source text.
715
716Save the file and do the same for Dutch working with \c tt2_nl.ts:
717
718\list
719\i \c ArrowPad
720 \list
721 \i \&Up - \&Boven
722 \i \&Left - \&Links
723 \i \&Right - \&Rechts
724 \i \&Down - \&Onder
725 \endlist
726\i \c MainWindow
727 \list
728 \i E\&xit - \&Afsluiten
729 \i Ctrl+Q - Ctrl+A
730 \i File - \&Bestand
731 \endlist
732\endlist
733
734We have to convert the \c tt1_fr.ts and \c tt1_nl.ts translation source
735files into \c .qm files. We could use \e {Qt Linguist} as we've done
736before; however using the command line tool \l lrelease ensures that
737\e all the \c .qm files for the application are created without us
738having to remember to load and \e File|Release each one
739individually from \e {Qt Linguist}.
740
741In practice we would include calls to \l lupdate and \l lrelease in the
742application's makefile to ensure that the latest translations are
743used.
744
745\omit
746an example of a makefile or .pro file that did this would be nice
747\endomit
748
749Type
750
751\code
752 lrelease tt2.pro
753\endcode
754
755\index LANG!Environment Variable
756\index export!Unix Command
757\index setenv!Unix Command
758
759This should create both \c tt2_fr.qm and \c tt2_nl.qm. Set the \c
760LANG environment variable to \c fr. In Unix, one of the two following
761commands should work
762
763\code
764 export LANG=fr
765 setenv LANG fr
766\endcode
767
768\index
769
770\index autoexec.bat
771\index set!Windows Command
772
773In Windows, either modify \c autoexec.bat or run
774
775\code
776 set LANG=fr
777\endcode
778
779When you run the program, you should now see the French version:
780
781\img tt2_fr.png
782\caption Tutorial 2 Screenshot, French version
783
784Try the same with Dutch, by setting \c LANG=nl. Now the Dutch
785version should appear:
786
787\img tt2_nl.png
788\caption Tutorial 2 Screenshot, Dutch version
789
790\section3 Exercises
791
792Mark one of the translations in \e {Qt Linguist} as not done, i.e.
793by unchecking the "done" checkbox; run \l lupdate, then \l lrelease,
794then the example. What effect did this change have?
795
796\index Canada
797\index French Canada
798
799Set \c LANG=fr_CA (French Canada) and run the example program again.
800Explain why the result is the same as with \c LANG=fr.
801
802Change one of the accelerators in the Dutch translation to eliminate the
803conflict between \e \&Bestand and \e \&Boven.
804
805
806\section2 Tutorial 3: Disambiguating Identical Strings
807
808\img tt3_10_en.png
809\caption Tutorial 3 Screenshot, "Troll Print 1.0", English version
810
811\include tt3/tt3.pro
812\caption \c tt3.pro
813
814\index Portuguese Language
815\index Brazilian Language
816
817We've included a translation file, \c tt3_pt.ts, which contains some
818Portuguese translations for this example.
819
820\index Troll Print
821
822We will consider two releases of the same application: Troll Print
8231.0 and 1.1. We will learn to reuse the translations created for one
824release in a subsequent release. (In this tutorial, you need to edit
825some source files. It's probably best to copy all the files to a new
826temporary directory and work from there.)
827
828Troll Print is a toy example application that lets the user choose
829printer settings. It comes in two versions: English and Portuguese.
830
831Version 1.0 consists of these files:
832
833\index tt3.pro
834\index tt3_pt.ts
835
836\list
837\i \c printpanel.h contains the definition of PrintPanel;
838\i \c printpanel.cpp contains the implementation of PrintPanel;
839\i \c mainwindow.h contains the definition of \c MainWindow;
840\i \c mainwindow.cpp contains the implementation of \c MainWindow;
841\i \c main.cpp contains main();
842\i \c tt3.pro is the \e qmake project file.
843\i \c tt3_pt.ts is the Portuguese message file.
844\endlist
845
846\section3 Line by Line Walk-through
847
848The PrintPanel is defined in \c printpanel.h.
849
850\quotefile tt3/printpanel.h
851\skipto QVBox
852\printline QVBox
853\printuntil Q_OBJECT
854
855\index Q_OBJECT
856
857\index PrintPanel!in Translation Tutorial
858
859PrintPanel is a \l QWidget. It needs the \c Q_OBJECT macro for \c
860tr() to work properly.
861
862The implementation file is \c printpanel.cpp.
863
864\quotefile tt3/printpanel.cpp
865\skipto setSpacing
866\skipto /
867\printline /
868\printline
869\printline
870\printline
871
872\index Troll Print
873
874Some of the code is commented out in Troll Print 1.0; you will uncomment
875it later, for Troll Print 1.1.
876
877\quotefile tt3/printpanel.cpp
878\skipto twoSided
879\printline twoSided
880\printuntil toggle
881\printline
882\printuntil toggle
883
884Notice the two occurrences of \c tr("Enabled") and of \c
885tr("Disabled") in PrintPanel. Since both "Enabled"s and "Disabled"s
886appear in the same context \e {Qt Linguist} will only display one
887occurrence of each and will use the same translations for the
888duplicates that it doesn't display. Whilst this is a useful
889timesaver, in some languages, such as Portuguese, the second
890occurrence requires a separate translation. We will see how \e {Qt
891Linguist} can be made to display all the occurrences for separate
892translation shortly.
893
894\index MainWindow!in Translation Tutorial
895
896The header file for \c MainWindow, \c mainwindow.h, contains no
897surprises. In the implementation, \c mainwindow.cpp, we have some
898user-visible source texts that must be marked for translation.
899
900\quotefile tt3/mainwindow.cpp
901\skipto setCaption
902\printline setCaption
903
904We must translate the window's caption.
905
906\skipto quit
907\printline quit
908\printuntil Help
909
910We also need to translate the menu items. Note that the two argument
911form of \c tr() is used for the keyboard accelerator, "Ctrl+Q", since
912the second argument is the only clue the translator has to indicate
913what function that accelerator will perform.
914
915\quotefile tt3/main.cpp
916\skipto QTranslator
917\printuntil installTranslator
918
919\index main()
920
921The \c main() function in \c main.cpp is the same as the one in \link
922{Tutorial 2...} Tutorial 2 \endlink. In particular it chooses a
923translation file based on the current locale.
924
925\section3 Running Troll Print 1.0 in English and in Portuguese
926
927We will use the translations in the \c tt3_pt.ts file that is provided.
928
929Set the \c LANG environment variable to \c pt, and then run \c tt3.
930You should still see the English version, as shown in the \e
931{Tutorial 3 Screenshot, "Troll Print 1.0", English version}, above.
932Now run \l lrelease, e.g. \c {lrelease tt3.pro}, and then run the
933example again. Now you should see the Portuguese edition (Troll
934Imprimir 1.0):
935
936\img tt3_10_pt_bad.png
937\caption Tutorial 3 Screenshot, "Troll Imprimir 1.0", (Bad) Portuguese version
938
939Whilst the translation has appeared correctly, it is in fact wrong. In
940good Portuguese, the second occurrence of "Enabled" should be
941"Ativadas", not "Ativado" and the ending for the second translation of
942"Disabled" must change similarly too.
943
944If you open \c tt3_pt.ts using \e {Qt Linguist}, you will see that
945there is just one occurrence of "Enabled" and of "Disabled" in the
946translation source file, even though there are two of each in the
947source code. This is because \e {Qt Linguist} tries to minimize the
948translator's work by using the same translation for duplicate source
949texts. In cases such as this where an identical translation is wrong,
950the programmer must disambiguate the duplicate occurrences. This is
951easily achieved by using the two argument form of \c tr().
952
953We can easily determine which file must be changed because the
954translator's "context" is in fact the class name for the class where
955the texts that must be changed appears. In this case the file is \c
956printpanel.cpp, where the there are four lines to change. Add the
957second argument "two-sided" in the appropriate \c tr() calls to the
958first pair of radio buttons:
959
960\code
961 but = new QRadioButton( tr("Enabled", "two-sided"), twoSided );
962 but = new QRadioButton( tr("Disabled", "two-sided"), twoSided );
963\endcode
964
965and add the second argument "colors" in the appropriate \c tr() calls
966for the second pair of radio buttons:
967
968\code
969 but = new QRadioButton( tr("Enabled", "colors"), colors );
970 but = new QRadioButton( tr("Disabled", "colors"), colors );
971\endcode
972
973\index lupdate
974\index tt3_pt.ts
975
976Now run \l lupdate and open \c tt3_pt.ts with \e {Qt Linguist}. You
977should now see two changes.
978
979First, the translation source file now contains \e three "Enabled",
980"Disabled" pairs. The first pair is marked "(obs.)" signifying that they
981are obsolete. This is because these texts appeared in \c tr() calls that
982have been replaced by new calls with two arguments. The second pair has
983"two-sided" as their comment, and the third pair has "colors" as their
984comment. The comments are shown in the \e {Source text and comments}
985area in \e {Qt Linguist}.
986
987Second, the translation text "Ativado" and "Desativado" have been
988automatically used as translations for the new "Enabled" and "Disabled"
989texts, again to minimize the translator's work. Of course in this case
990these are not correct for the second occurrence of each word, but they
991provide a good starting point.
992
993Change the second "Ativado" into "Ativadas" and the second
994"Desativado" into "Desativadas", then save and quit. Run \l lrelease
995to obtain an up-to-date binary \c tt3_pt.qm file, and run Troll Print
996(or rather Troll Imprimir).
997
998\img tt3_10_pt_good.png
999\caption Tutorial 3 Screenshot, "Troll Imprimir 1.0", (Good) Portuguese version
1000
1001\index Translator Comments
1002\index Comments!for Translators
1003
1004The second argument to \c tr() calls, called "comments" in \e {Qt
1005Linguist}, distinguish between identical source texts that occur in
1006the same context (class). They are also useful in other cases to give
1007clues to the translator, and in the case of Ctrl key accelerators are
1008the only means of conveying the function performed by the accelerator to
1009the translator.
1010
1011\index TRANSLATOR!in Comments
1012\index Translator Comments
1013\index Comments!for Translators
1014
1015An additional way of helping the translator is to provide information on
1016how to navigate to the particular part of the application that contains
1017the source texts they must translate. This helps them see the context
1018in which the translation appears and also helps them to find and test
1019the translations. This can be achieved by using a \e TRANSLATOR comment
1020in the source code:
1021\code
1022 /* TRANSLATOR MainWindow
1023
1024 In this application the whole application is a MainWindow.
1025 Choose Help|About from the menu bar to see some text
1026 belonging to MainWindow.
1027 */
1028\endcode
1029
1030Try adding these comments to some source files, particularly to
1031dialog classes, describing the navigation necessary to reach the
1032dialogs. You could also add them to the example files, e.g. \c
1033mainwindow.cpp and \c printpanel.cpp are appropriate files. Run \l
1034lupdate and then start \e {Qt Linguist} and load in \c tt3_pt.ts.
1035You should see the comments in the \e {Source text and comments} area
1036as you browse through the list of source texts.
1037
1038Sometimes, particularly with large programs, it can be difficult for
1039the translator to find their translations and check that they're
1040correct. Comments that provide good navigation information can save
1041them time:
1042
1043\code
1044 /* TRANSLATOR ZClientErrorDialog
1045
1046 Choose Client|Edit to reach the Client Edit dialog, then choose
1047 Client Specification from the drop down list at the top and pick
1048 client Bartel Leendert van der Waerden. Now check the Profile
1049 checkbox and then click the Start Processing button. You should
1050 now see a pop up window with the text "Error: Name too long!".
1051 This window is a ZClientErrorDialog.
1052 */
1053\endcode
1054
1055
1056\section3 Troll Print 1.1
1057
1058We'll now prepare release 1.1 of Troll Print. Start your favorite text
1059editor and follow these steps:
1060
1061\list
1062\i Uncomment the two lines that create a \l QLabel with the text
1063 "\<b\>TROLL PRINT\</b\>" in \c printpanel.cpp.
1064\i Word-tidying: Replace "2-sided" by "Two-sided" in \c printpanel.cpp.
1065\i Replace "1.0" with "1.1" everywhere it occurs in \c mainwindow.cpp.
1066\i Update the copyright year to 1999-2000 in \c mainwindow.cpp.
1067\endlist
1068
1069(Of course the version number and copyright year would be consts or
1070#defines in a real application.)
1071
1072Once finished, run \l lupdate, then open \c tt3_pt.ts in \e {Qt
1073Linguist}. The following items are of special interest:
1074
1075\list
1076\i \c MainWindow
1077 \list
1078 \i Troll Print 1.0 - marked "(obs.)", obsolete
1079 \i About Troll Print 1.0 - marked "(obs.)", obsolete
1080 \i Troll Print 1.0. Copyright 1999 Macroshaft, Inc. -
1081 marked "(obs.)", obsolete
1082 \i Troll Print 1.1 - automatically translated as
1083 "Troll Imprimir 1.1"
1084 \i About Troll Print 1.1 - automatically translated as
1085 "Troll Imprimir 1.1"
1086 \i Troll Print 1.1. Copyright 1999-2000 Macroshaft,
1087 Inc. - automatically translated as "Troll Imprimir 1.1.
1088 Copyright 1999-2000 Macroshaft, Inc."
1089 \endlist
1090\i \c PrintPanel
1091 \list
1092 \i 2-sided - marked "(obs.)", obsolete
1093 \i \<b\>TROLL PRINT\</b\> - unmarked, i.e. untranslated
1094 \i Two-sided - unmarked, i.e. untranslated.
1095 \endlist
1096\endlist
1097
1098Notice that \l lupdate works hard behind the scenes to make revisions
1099easier, and it's pretty smart with numbers.
1100
1101Go over the translations in \c MainWindow and mark these as "done".
1102Translate "\<b\>TROLL PRINT\</b\>" as "\<b\>TROLL IMPRIMIR\</b\>".
1103When you're translating "Two-sided", press the \e {Guess Again}
1104button to translate "Two-sided", but change the "2" into "Dois".
1105
1106Save and quit, then run \l lrelease. The Portuguese version
1107should look like this:
1108
1109\img tt3_11_pt.png
1110\caption Tutorial 3 Screenshot, "Troll Imprimir 1.1", Portuguese version
1111
1112Choose \e{Ajuda|Sobre}, (\e{Help|About}), to see the about box
1113
1114\img tt3_11_about_pt.png
1115\caption Tutorial 3 Screenshot, About box, Portuguese version
1116
1117\index English Language
1118\index Translating Qt
1119\index Qt!Translating Qt
1120
1121If you choose \e {Ajuda|Sobre Qt}, (\e {Help|About Qt}), you'll get
1122an English dialog. Oops! Qt itself needs to be translated. See the
1123document \link i18n.html#qt-itself Internationalization with Qt
1124\endlink for details.
1125
1126Now set \c LANG=en to get the original English version:
1127
1128\img tt3_11_en.png
1129\caption Tutorial 3 Screenshot, "Troll Print 1.1", English version
1130
1131\section2 Summary
1132
1133These tutorials cover all that you need to know to prepare your Qt
1134applications for translation.
1135
1136At the beginning of a project add the translation source files to be
1137used to the project file and add calls to \l lupdate and \l lrelease to
1138the make file.
1139
1140During the project all the programmer must do is wrap any user-visible
1141text in \c tr() calls. They should also use the two argument form for
1142Ctrl key accelerators, or when asked by the translator for the cases
1143where the same text translates into two different forms in the same
1144context. The programmer should also include \e TRANSLATION comments to
1145help the translator navigate the application.
Note: See TracBrowser for help on using the repository browser.