diff options
Diffstat (limited to 'tools/linguist/book/linguist-programmer.leaf')
-rw-r--r-- | tools/linguist/book/linguist-programmer.leaf | 1145 |
1 files changed, 1145 insertions, 0 deletions
diff --git a/tools/linguist/book/linguist-programmer.leaf b/tools/linguist/book/linguist-programmer.leaf new file mode 100644 index 0000000..d2a079b --- /dev/null +++ b/tools/linguist/book/linguist-programmer.leaf @@ -0,0 +1,1145 @@ +\chapter Programmers + +Support for multiple languages is extremely simple in Qt +applications, and adds little overhead to the programmer's workload. + +Qt minimizes the performance cost of using translations by +translating the phrases for each window as they are created. In most +applications the main window is created just once. Dialogs are often +created once and then shown and hidden as required. Once the initial +translation has taken place there is no further runtime overhead for +the translated windows. Only those windows that are created, +destroyed and subsequently created will have a translation +performance cost. + +Creating applications that can switch language at runtime is possible +with Qt, but requires a certain amount of programmer intervention and +will of course incur some runtime performance cost. + +\section1 Making the Application Translation Aware + +Programmers should make their application look for and load the +appropriate translation file and mark user-visible text and Ctrl +keyboard accelerators as targets for translation. + +Each piece of text that requires translating requires context to help +the translator identify where in the program the text occurs. In the +case of multiple identical texts that require different translations, +the translator also requires some information to disambiguate the +source texts. Marking text for translation will automatically cause +the class name to be used as basic context information. In some cases +the programmer may be required to add additional information to help +the translator. + +\section2 Creating Translation Files + +\index .ts Files +\index Translation Source Files + +Translation files consist of all the user-visible text and Ctrl key +accelerators in an application and translations of that text. +Translation files are created as follows: + +\index lupdate +\index lrelease + +\list 1 +\i Run \l lupdate initially to generate the first set of \c .ts +translation source files with all the user-visible text but no +translations. +\i The \c .ts files are given to the translator who adds translations +using \e {Qt Linguist}. \e {Qt Linguist} takes care of any changed +or deleted source text. +\i Run \l lupdate to incorporate any new text added to the +application. \l lupdate synchronizes the user-visible text from the +application with the translations; it does not destroy any data. +\i Steps 2 and 3 are repeated as often as necessary. +\i When a release of the application is needed \l lrelease is run to +read the \c .ts files and produce the \c .qm files used by the +application at runtime. +\endlist + +\index .pro Files +\index Project Files +\index qmake!Project Files + +For \l lupdate to work successfully, it must know which translation +files to produce. The files are simply listed in the application's \c +.pro Qt project file, for example: +\quotefile tt2/tt2.pro +\skipto TRANSLATIONS +\printline TRANSLATIONS +\printline + +See the \link lupdate "lupdate" \endlink and \link lrelease +"lrelease" \endlink sections. + +\section2 Loading Translations + +\quotefile tt1/main.cpp +\skipto main( +\printline main( +\printuntil QApplication + +\index main() + +This is how a simple \c main() function of a Qt application begins. + +\index QTranslator!load() +\index load()!QTranslator +\index QApplication!installTranslator() +\index installTranslator()!QApplication + +\quotefile tt1/main.cpp +\skipto main( +\printline main( +\printuntil app.installTrans + +For a translation-aware application a translator object is created, a +translation is loaded and the translator object installed into the +application. + +\quotefile tt2/main.cpp +\skipto main( +\printline main( +\printuntil app.installTrans + +In production applications a more flexible approach, for example, +loading translations according to locale, might be more appropriate. If +the \c .ts files are all named according to a convention such as +\e appname_locale, e.g. \c tt2_fr, \c tt2_de etc, then the +code above will load the current locale's translation at runtime. + +If there is no translation file for the current locale the application +will fall back to using the original source text. + +\section2 Making the Application Translate User-Visible Strings + +\index tr() +\index QObject!tr() + +User-visible strings are marked as translation targets by wrapping them +in a \c tr() call, for example: +\code + button = new QPushButton( "&Quit", this ); +\endcode + +would become + +\code + button = new QPushButton( tr("&Quit"), this); +\endcode + +\index Q_OBJECT + +All \l QObject subclasses that use the \c Q_OBJECT macro implement +the \c tr() function. + +Although the \c tr() call is normally made directly since it is +usually called as a member function of a \l QObject subclass, in +other cases an explicit class name can be supplied, for example: + +\code + QPushButton::tr("&Quit") +\endcode + +or + +\code + QObject::tr("&Quit") +\endcode + +\section2 Distinguishing Identical Strings That Require Different +Translations + +\index Translation Contexts +\index Contexts!for Translation +\index lupdate + +The \l lupdate program automatically provides a \e context for every +source text. This context is the class name of the class that contains +the \c tr() call. This is sufficient in the vast majority of cases. +Sometimes however, the translator will need further information to +uniquely identify a source text; for example, a dialog that contained +two separate frames, each of which contained an "Enabled" option would +need each identified because in some languages the translation would +differ between the two. This is easily achieved using the +two argument form of the \c tr() call, e.g. + +\code + rbc = new QRadioButton( tr("Enabled", "Color frame"), this ); +\endcode + +and + +\code + rbh = new QRadioButton( tr("Enabled", "Hue frame"), this ); +\endcode + +\index Ctrl Key + +Ctrl key accelerators are also translatable: + +\quotefile tt3/mainwindow.cpp +\skipto quit() +\printline quit() +\printuntil Quit + +It is strongly recommended that the two argument form of \c tr() is used +for Ctrl key accelerators. The second argument is the only clue the +translator has as to the function performed by the accelerator. + +\section2 Helping The Translator With Navigation Information + +\index TRANSLATOR!in Comments +\index Translator Comments +\index Comments!for Translators + +In large complex applications it may be difficult for the translator to +see where a particular source text comes from. This problem can be +solved by adding a comment using the keyword \e TRANSLATOR which +describes the navigation steps to reach the text in question; e.g. + +\code + /* TRANSLATOR FindDialog + + Choose Edit|Find from the menu bar or press Ctrl+F to pop up the + Find dialog. + */ +\endcode + +These comments are particularly useful for widget classes. + +\section2 Coping With C++ Namespaces + +\index Namespaces +\index C++!Namespaces +\index lupdate + +C++ namespaces and the \c {using namespace} statement can confuse +\l lupdate. It will interpret \c MyClass::tr() as meaning just +that, not as \c MyNamespace::MyClass::tr(), even if \c MyClass is +defined in the \c MyNamespace namespace. Runtime translation of +these strings will fail because of that. + +\index TRANSLATOR!in Comments +\index Translator Comments +\index Comments!for Translators + +You can work around this limitation by putting a \e TRANSLATOR +comment at the beginning of the source files that use \c +MyClass::tr(): +\code + /* TRANSLATOR MyNamespace::MyClass */ +\endcode +After the comment, all references to \c MyClass::tr() will be +understood as meaning \c MyNamespace::MyClass::tr(). + +\section2 Translating Text that is Outside of a QObject subclass + +\section3 Using QApplication::translate() + +If the quoted text is not in a member function of a QObject subclass, +use either the tr() function of an appropriate class, or the +QApplication::translate() function directly: + +\code + void some_global_function( LoginWidget *logwid ) + { + QLabel *label = new QLabel( + LoginWidget::tr("Password:"), logwid ); + } + + void same_global_function( LoginWidget *logwid ) + { + QLabel *label = new QLabel( + qApp->translate("LoginWidget", "Password:"), + logwid ); + } +\endcode + +\section3 Using QT_TR_NOOP() and QT_TRANSLATE_NOOP() + +If you need to have translatable text completely outside a function, +there are two macros to help: QT_TR_NOOP() and QT_TRANSLATE_NOOP(). +These macros merely mark the text for extraction by \l{lupdate}. +The macros expand to just the text (without the context). + +Example of QT_TR_NOOP(): +\code + QString FriendlyConversation::greeting( int greet_type ) + { + static const char* greeting_strings[] = { + QT_TR_NOOP( "Hello" ), + QT_TR_NOOP( "Goodbye" ) + }; + return tr( greeting_strings[greet_type] ); + } +\endcode + +Example of QT_TRANSLATE_NOOP(): +\code + static const char* greeting_strings[] = { + QT_TRANSLATE_NOOP( "FriendlyConversation", "Hello" ), + QT_TRANSLATE_NOOP( "FriendlyConversation", "Goodbye" ) + }; + + QString FriendlyConversation::greeting( int greet_type ) + { + return tr( greeting_strings[greet_type] ); + } + + QString global_greeting( int greet_type ) + { + return qApp->translate( "FriendlyConversation", + greeting_strings[greet_type] ); + } +\endcode + +\section1 Tutorials + +Three tutorials are presented. The first demonstrates the creation of +a \l QTranslator object. It also shows the simplest use of the \c +tr() function to mark user-visible source text for translation. The +second tutorial explains how to make the application load the +translation file applicable to the current locale. It also shows the +use of the two-argument form of \c tr() which provides additional +information to the translator. The third tutorial explains how +identical source texts can be distinguished even when they occur in +the same context. This tutorial also discusses how the translation +tools help minimize the translator's work when an application is +upgraded. + +\section2 Tutorial 1: Loading and Using Translations + +\img tt1_en.png +\caption Tutorial 1 Screenshot, English version + +\include tt1/tt1.pro +\caption \c tt1.pro + +\include tt1/main.cpp +\caption \c main.cpp + +This example is a reworking of the \link tutorial1-01.html +"hello-world" \endlink example from \link tutorial.html Tutorial +#1\endlink, with a Latin translation. The \e {Tutorial 1 Screenshot, +English version}, above, shows the English version. + +\quotefile tt1/main.cpp + +\section3 Line by Line Walk-through + +\quotefile tt1/main.cpp + +\skipto qtranslator +\printline qtranslator + +\index QTranslator + +This line includes the definition of the \l QTranslator class. +Objects of this class provide translations for user-visible text. + +\skipto QTranslator +\printuntil tor + +Creates a \l QTranslator object without a parent. + +\printline load + +\index tt1_la.qm + +Tries to load a file called \c tt1_la.qm (the \c .qm file extension is +implicit) that contains Latin translations for the source texts used in +the program. No error will occur if the file is not found. + +\index QApplication!installTranslator() +\index installTranslator()!QApplication + +\printline installTranslator + +Adds the translations from \c tt1_la.qm to the pool of translations used +by the program. + +\index Hello World + +\printline hello + +Creates a push button that displays "Hello world!". If \c tt1_la.qm +was found and contains a translation for "Hello world!", the +translation appears; if not, the source text appears. + +\index tr() +\index QObject!tr() + +All classes that inherit \l QObject have a \c tr() function. Inside +a member function of a \l QObject class, we simply write \c tr("Hello +world!") instead of \c QPushButton::tr("Hello world!") or \c +QObject::tr("Hello world!"). + +\section3 Running the Application in English + +\index English Language + +Since we haven't made the translation file \c tt1_la.qm, the source text +is shown when we run the application: + +\img tt1_en.png +\caption Tutorial 1 Screenshot, English version + +\section3 Creating a Latin Message File + +\index tt1.pro +\index Latin + +The first step is to create a project file, \c tt1.pro, that lists +all the source files for the project. The project file can be a qmake +project file, or even an ordinary makefile. Any file that contains + +\index SOURCES!in Project Files +\index TRANSLATIONS!in Project Files + +\quotefile tt1/tt1.pro +\skipto SOURCES +\printline SOURCES +\skipto TRANSLATIONS +\printline TRANSLATIONS + +will work. \e TRANSLATIONS specifies the message files we want to +maintain. In this example, we just maintain one set of translations, +namely Latin. + +\index .ts Files +\index Translation Source Files +\index .qm Files +\index Qt Message Files + +Note that the file extension is \c .ts, not \c .qm. The \c .ts +translation source format is designed for use during the +application's development. Programmers or release managers run the \l +lupdate program to generate and update \c .ts files with the source +text that is extracted from the source code. Translators read and +update the \c .ts files using \e {Qt Linguist} adding and editing +their translations. + +\index XML + +The \c .ts format is human-readable XML that can be emailed directly +and is easy to put under version control. If you edit this file +manually, be aware that the default encoding for XML is UTF-8, not +Latin-1 (ISO 8859-1). One way to type in a Latin-1 character such as +'\OSLASH' (Norwegian o with slash) is to use an XML entity: +"\ø". This will work for any Unicode character. + +Once the translations are complete the \l lrelease program is used to +convert the \c .ts files into the \c .qm Qt message file format. The +\c .qm format is a compact binary format designed to deliver very +fast lookup performance. Both \l lupdate and \l lrelease read all the +project's source and header files (as specified in the HEADERS and +SOURCES lines of the project file) and extract the strings that +appear in \c tr() function calls. + +\index lupdate + +\l lupdate is used to create and update the message files (\c tt1_la.ts +in this case) to keep them in sync with the source code. It is safe to +run \l lupdate at any time, as \l lupdate does not remove any +information. For example, you can put it in the makefile, so the \c .ts +files are updated whenever the source changes. + +\index .ts Files +\index Translation Source Files +\index XML + +Try running \l lupdate right now, like this: +\code + lupdate -verbose tt1.pro +\endcode +(The \c -verbose option instructs \c lupdate to display messages that +explain what it is doing.) You should now have a file \c tt1_la.ts in +the current directory, containing this: +\code + <!DOCTYPE TS><TS> + <context> + <name>QPushButton</name> + <message> + <source>Hello world!</source> + <translation type="unfinished"></translation> + </message> + </context> + </TS> +\endcode +You don't need to understand the file format since it is read and +updated using tools (\l lupdate, \e {Qt Linguist}, \l lrelease). + +\section3 Translating to Latin with Qt Linguist + +\index Qt Linguist +\index Linguist + +We will use \e {Qt Linguist} to provide the translation, although +you can use any XML or plain text editor to enter a translation into a +\c .ts file. + +To start \e {Qt Linguist}, type +\code + linguist tt1_la.ts +\endcode + +You should now see the text "QPushButton" in the top left pane. +Double-click it, then click on "Hello world!" and enter "Orbis, te +saluto!" in the \e Translation pane (the middle right of the +window). Don't forget the exclamation mark! + +Click the \e Done checkbox and choose \e File|Save from the +menu bar. The \c .ts file will no longer contain +\code + <translation type='unfinished'></translation> +\endcode +but instead will have +\code + <translation>Orbis, te saluto!</translation> +\endcode + +\section3 Running the Application in Latin + +\index Latin +\index lrelease + +To see the application running in Latin, we have to generate a \c .qm +file from the \c .ts file. Generating a \c .qm file can be achieved +either from within \e {Qt Linguist} (for a single \c .ts file), or +by using the command line program \l lrelease which will produce one \c +.qm file for each of the \c .ts files listed in the project file. +Generate \c tt1_la.qm from \c tt1_la.ts by choosing +\e File|Release from \e {Qt Linguist}'s menu bar and pressing +\e Save in the file save dialog that pops up. Now run the \e tt1 example +program again. This time the button will be labelled "Orbis, te +saluto!". + +\img tt1_la.png +\caption Tutorial 1 Screenshot, Latin version + +\section2 Tutorial 2: Using Two or More Languages + +\img tt2_en.png +\caption Tutorial 2 Screenshot, English version + +\index .pro Files +\index Project Files +\index qmake!Project Files + +\include tt2/tt2.pro +\caption tt2.pro + +\index Translation Contexts +\index Contexts!for Translation + +This example is a slightly more involved and introduces a key +\e {Qt Linguist} concept: "contexts". + +\list +\i \c arrowpad.h contains the definition of \c ArrowPad, a custom widget; +\i \c arrowpad.cpp contains the implementation of \c ArrowPad; +\i \c mainwindow.h contains the definition of \c MainWindow, a subclass of + \l QMainWindow +\i \c mainwindow.cpp contains the implementation of \c MainWindow; +\i \c main.cpp contains main(). +\endlist + +\index tt2.pro +\index French Language +\index Dutch Language + +We will use two translations, French and Dutch, although there is no +effective limit on the number of possible translations that can be used +with an application. The relevant lines of \c tt2.pro are + +\quotefile tt2/tt2.pro +\skipto HEADERS +\printuntil tt2_nl.ts + +\index lupdate +\index tt2_fr.ts +\index tt2_nl.ts + +Run \l lupdate; it should produce two identical message files +\c tt2_fr.ts and \c tt2_nl.ts. These files will contain all the source +texts marked for translation with \c tr() calls and their contexts. + +\section3 Line by Line Walk-through + +\index ArrowPad!in Translation Tutorial +\index English Language + +In \c arrowpad.h we define the \c ArrowPad subclass which is a +subclass of \l QWidget. In the \e {Tutorial 2 Screenshot, English +version}, above, the central widget with the four buttons is an +\c ArrowPad. + +\quotefile tt2/arrowpad.h +\skipto class ArrowPad +\printline class ArrowPad + +\index Q_OBJECT +\index tr() +\index QObject!tr() +\index Translation Contexts +\index Contexts!for Translation + +When \l lupdate is run it not only extracts the source texts but it +also groups them into contexts. A context is the name of the class in +which the source text appears. Thus, in this example, "ArrowPad" is a +context: it is the context of the texts in the \c ArrowPad class. +The \c Q_OBJECT macro defines \c tr(x) in \c ArrowPad like this + +\index QApplication!translate() +\index translate()!QApplication + +\code + qApp->translate( "ArrowPad", x ) +\endcode + +Knowing which class each source text appears in enables \e {Qt +Linguist} to group texts that are logically related together, e.g. +all the text in a dialog will have the context of the dialog's class +name and will be shown together. This provides useful information for +the translator since the context in which text appears may influence how +it should be translated. For some translations keyboard +accelerators may need to be changed and having all the source texts in a +particular context (class) grouped together makes it easier for the +translator to perform any accelerator changes without introducing +conflicts. + +In \c arrowpad.cpp we implement the \c ArrowPad class. + +\quotefile tt2/arrowpad.cpp +\skipto QPushButton +\printline QPushButton + +We call \c ArrowPad::tr() for each button's label since the labels are +user-visible text. + +\img tt2_en.png +\caption Tutorial 2 Screenshot, English version + +\index Q_OBJECT +\index MainWindow!in Translation Tutorial + +\quotefile tt2/mainwindow.h +\skipto QMainWindow +\printline QMainWindow +\printuntil Q_OBJECT + +In the \e {Tutorial 2 Screenshot, English version}, above, the whole +window is a \c MainWindow. This is defined in the \c mainwindow.h +header file. Here too, we use \c Q_OBJECT, so that \c MainWindow will +become a context in \e {Qt Linguist}. + +In the implementation of \c MainWindow, \c mainwindow.cpp, we create +an instance of our \c ArrowPad class + +\quotefile tt2/mainwindow.cpp +\skipto arrow pad +\printline arrow pad + +We also call \c MainWindow::tr() twice, once for the menu item and +once for the accelerator. + +\index Ctrl Key +\index Alt Key + +\skipto quit() +\printline quit() +\printuntil Ctrl+Q + +Note the use of \c tr() to support different keys in other languages. +"Ctrl+Q" is a good choice for Quit in English, but a Dutch translator +might want to use "Ctrl+A" (for Afsluiten) and a German translator +"Strg+E" (for Beenden). When using \c tr() for Ctrl key accelerators, +the two argument form should be used with the second argument +describing the function that the accelerator performs. + +\index main() + +Our \c main() function is defined in \c main.cpp as usual. + +\quotefile tt2/main.cpp +\skipto QTranslator +\printline QTranslator +\printuntil install + +\index QTextCodec!locale() +\index locale()!QTextCodec +\index LANG!Environment Variable +\index Environment Variables!LANG + +We choose which translation to use according to the current locale. +\l QTextCodec::locale() can be influenced by setting the \c LANG +environment variable, for example. Notice that the use of a naming +convention that incorporates the locale for \c .qm message files, +(and \c .ts files), makes it easy to implement choosing the +translation file according to locale. + +If there is no \c .qm message file for the locale chosen the original +source text will be used and no error raised. + +\section3 Translating to French and Dutch + +We'll begin by translating the example application into French. Start +\e {Qt Linguist} with \c tt2_fr.ts. You should get the seven source +texts ("\&Up", "\&Left", etc.) grouped in two contexts ("ArrowPad" +and "MainWindow"). + +Now, enter the following translations: + +\list +\i \c ArrowPad + \list + \i \&Up - \&Haut + \i \&Left - \&Gauche + \i \&Right - \&Droite + \i \&Down - \&Bas + \endlist +\i \c MainWindow + \list + \i E\&xit - \&Quitter + \i Ctrl+Q - Ctrl+Q + \i \&File - \&Fichier + \endlist +\endlist + +It's quickest to press \Key Alt+D (which clicks the \e {Done \& Next} +button) after typing each translation, since this marks the +translation as done and moves on to the next source text. + +Save the file and do the same for Dutch working with \c tt2_nl.ts: + +\list +\i \c ArrowPad + \list + \i \&Up - \&Boven + \i \&Left - \&Links + \i \&Right - \&Rechts + \i \&Down - \&Onder + \endlist +\i \c MainWindow + \list + \i E\&xit - \&Afsluiten + \i Ctrl+Q - Ctrl+A + \i File - \&Bestand + \endlist +\endlist + +We have to convert the \c tt1_fr.ts and \c tt1_nl.ts translation source +files into \c .qm files. We could use \e {Qt Linguist} as we've done +before; however using the command line tool \l lrelease ensures that +\e all the \c .qm files for the application are created without us +having to remember to load and \e File|Release each one +individually from \e {Qt Linguist}. + +In practice we would include calls to \l lupdate and \l lrelease in the +application's makefile to ensure that the latest translations are +used. + +\omit +an example of a makefile or .pro file that did this would be nice +\endomit + +Type + +\code + lrelease tt2.pro +\endcode + +\index LANG!Environment Variable +\index export!Unix Command +\index setenv!Unix Command + +This should create both \c tt2_fr.qm and \c tt2_nl.qm. Set the \c +LANG environment variable to \c fr. In Unix, one of the two following +commands should work + +\code + export LANG=fr + setenv LANG fr +\endcode + +\index + +\index autoexec.bat +\index set!Windows Command + +In Windows, either modify \c autoexec.bat or run + +\code + set LANG=fr +\endcode + +When you run the program, you should now see the French version: + +\img tt2_fr.png +\caption Tutorial 2 Screenshot, French version + +Try the same with Dutch, by setting \c LANG=nl. Now the Dutch +version should appear: + +\img tt2_nl.png +\caption Tutorial 2 Screenshot, Dutch version + +\section3 Exercises + +Mark one of the translations in \e {Qt Linguist} as not done, i.e. +by unchecking the "done" checkbox; run \l lupdate, then \l lrelease, +then the example. What effect did this change have? + +\index Canada +\index French Canada + +Set \c LANG=fr_CA (French Canada) and run the example program again. +Explain why the result is the same as with \c LANG=fr. + +Change one of the accelerators in the Dutch translation to eliminate the +conflict between \e \&Bestand and \e \&Boven. + + +\section2 Tutorial 3: Disambiguating Identical Strings + +\img tt3_10_en.png +\caption Tutorial 3 Screenshot, "Troll Print 1.0", English version + +\include tt3/tt3.pro +\caption \c tt3.pro + +\index Portuguese Language +\index Brazilian Language + +We've included a translation file, \c tt3_pt.ts, which contains some +Portuguese translations for this example. + +\index Troll Print + +We will consider two releases of the same application: Troll Print +1.0 and 1.1. We will learn to reuse the translations created for one +release in a subsequent release. (In this tutorial, you need to edit +some source files. It's probably best to copy all the files to a new +temporary directory and work from there.) + +Troll Print is a toy example application that lets the user choose +printer settings. It comes in two versions: English and Portuguese. + +Version 1.0 consists of these files: + +\index tt3.pro +\index tt3_pt.ts + +\list +\i \c printpanel.h contains the definition of PrintPanel; +\i \c printpanel.cpp contains the implementation of PrintPanel; +\i \c mainwindow.h contains the definition of \c MainWindow; +\i \c mainwindow.cpp contains the implementation of \c MainWindow; +\i \c main.cpp contains main(); +\i \c tt3.pro is the \e qmake project file. +\i \c tt3_pt.ts is the Portuguese message file. +\endlist + +\section3 Line by Line Walk-through + +The PrintPanel is defined in \c printpanel.h. + +\quotefile tt3/printpanel.h +\skipto QVBox +\printline QVBox +\printuntil Q_OBJECT + +\index Q_OBJECT + +\index PrintPanel!in Translation Tutorial + +PrintPanel is a \l QWidget. It needs the \c Q_OBJECT macro for \c +tr() to work properly. + +The implementation file is \c printpanel.cpp. + +\quotefile tt3/printpanel.cpp +\skipto setSpacing +\skipto / +\printline / +\printline +\printline +\printline + +\index Troll Print + +Some of the code is commented out in Troll Print 1.0; you will uncomment +it later, for Troll Print 1.1. + +\quotefile tt3/printpanel.cpp +\skipto twoSided +\printline twoSided +\printuntil toggle +\printline +\printuntil toggle + +Notice the two occurrences of \c tr("Enabled") and of \c +tr("Disabled") in PrintPanel. Since both "Enabled"s and "Disabled"s +appear in the same context \e {Qt Linguist} will only display one +occurrence of each and will use the same translations for the +duplicates that it doesn't display. Whilst this is a useful +timesaver, in some languages, such as Portuguese, the second +occurrence requires a separate translation. We will see how \e {Qt +Linguist} can be made to display all the occurrences for separate +translation shortly. + +\index MainWindow!in Translation Tutorial + +The header file for \c MainWindow, \c mainwindow.h, contains no +surprises. In the implementation, \c mainwindow.cpp, we have some +user-visible source texts that must be marked for translation. + +\quotefile tt3/mainwindow.cpp +\skipto setCaption +\printline setCaption + +We must translate the window's caption. + +\skipto quit +\printline quit +\printuntil Help + +We also need to translate the menu items. Note that the two argument +form of \c tr() is used for the keyboard accelerator, "Ctrl+Q", since +the second argument is the only clue the translator has to indicate +what function that accelerator will perform. + +\quotefile tt3/main.cpp +\skipto QTranslator +\printuntil installTranslator + +\index main() + +The \c main() function in \c main.cpp is the same as the one in \link +{Tutorial 2...} Tutorial 2 \endlink. In particular it chooses a +translation file based on the current locale. + +\section3 Running Troll Print 1.0 in English and in Portuguese + +We will use the translations in the \c tt3_pt.ts file that is provided. + +Set the \c LANG environment variable to \c pt, and then run \c tt3. +You should still see the English version, as shown in the \e +{Tutorial 3 Screenshot, "Troll Print 1.0", English version}, above. +Now run \l lrelease, e.g. \c {lrelease tt3.pro}, and then run the +example again. Now you should see the Portuguese edition (Troll +Imprimir 1.0): + +\img tt3_10_pt_bad.png +\caption Tutorial 3 Screenshot, "Troll Imprimir 1.0", (Bad) Portuguese version + +Whilst the translation has appeared correctly, it is in fact wrong. In +good Portuguese, the second occurrence of "Enabled" should be +"Ativadas", not "Ativado" and the ending for the second translation of +"Disabled" must change similarly too. + +If you open \c tt3_pt.ts using \e {Qt Linguist}, you will see that +there is just one occurrence of "Enabled" and of "Disabled" in the +translation source file, even though there are two of each in the +source code. This is because \e {Qt Linguist} tries to minimize the +translator's work by using the same translation for duplicate source +texts. In cases such as this where an identical translation is wrong, +the programmer must disambiguate the duplicate occurrences. This is +easily achieved by using the two argument form of \c tr(). + +We can easily determine which file must be changed because the +translator's "context" is in fact the class name for the class where +the texts that must be changed appears. In this case the file is \c +printpanel.cpp, where the there are four lines to change. Add the +second argument "two-sided" in the appropriate \c tr() calls to the +first pair of radio buttons: + +\code + but = new QRadioButton( tr("Enabled", "two-sided"), twoSided ); + but = new QRadioButton( tr("Disabled", "two-sided"), twoSided ); +\endcode + +and add the second argument "colors" in the appropriate \c tr() calls +for the second pair of radio buttons: + +\code + but = new QRadioButton( tr("Enabled", "colors"), colors ); + but = new QRadioButton( tr("Disabled", "colors"), colors ); +\endcode + +\index lupdate +\index tt3_pt.ts + +Now run \l lupdate and open \c tt3_pt.ts with \e {Qt Linguist}. You +should now see two changes. + +First, the translation source file now contains \e three "Enabled", +"Disabled" pairs. The first pair is marked "(obs.)" signifying that they +are obsolete. This is because these texts appeared in \c tr() calls that +have been replaced by new calls with two arguments. The second pair has +"two-sided" as their comment, and the third pair has "colors" as their +comment. The comments are shown in the \e {Source text and comments} +area in \e {Qt Linguist}. + +Second, the translation text "Ativado" and "Desativado" have been +automatically used as translations for the new "Enabled" and "Disabled" +texts, again to minimize the translator's work. Of course in this case +these are not correct for the second occurrence of each word, but they +provide a good starting point. + +Change the second "Ativado" into "Ativadas" and the second +"Desativado" into "Desativadas", then save and quit. Run \l lrelease +to obtain an up-to-date binary \c tt3_pt.qm file, and run Troll Print +(or rather Troll Imprimir). + +\img tt3_10_pt_good.png +\caption Tutorial 3 Screenshot, "Troll Imprimir 1.0", (Good) Portuguese version + +\index Translator Comments +\index Comments!for Translators + +The second argument to \c tr() calls, called "comments" in \e {Qt +Linguist}, distinguish between identical source texts that occur in +the same context (class). They are also useful in other cases to give +clues to the translator, and in the case of Ctrl key accelerators are +the only means of conveying the function performed by the accelerator to +the translator. + +\index TRANSLATOR!in Comments +\index Translator Comments +\index Comments!for Translators + +An additional way of helping the translator is to provide information on +how to navigate to the particular part of the application that contains +the source texts they must translate. This helps them see the context +in which the translation appears and also helps them to find and test +the translations. This can be achieved by using a \e TRANSLATOR comment +in the source code: +\code + /* TRANSLATOR MainWindow + + In this application the whole application is a MainWindow. + Choose Help|About from the menu bar to see some text + belonging to MainWindow. + */ +\endcode + +Try adding these comments to some source files, particularly to +dialog classes, describing the navigation necessary to reach the +dialogs. You could also add them to the example files, e.g. \c +mainwindow.cpp and \c printpanel.cpp are appropriate files. Run \l +lupdate and then start \e {Qt Linguist} and load in \c tt3_pt.ts. +You should see the comments in the \e {Source text and comments} area +as you browse through the list of source texts. + +Sometimes, particularly with large programs, it can be difficult for +the translator to find their translations and check that they're +correct. Comments that provide good navigation information can save +them time: + +\code + /* TRANSLATOR ZClientErrorDialog + + Choose Client|Edit to reach the Client Edit dialog, then choose + Client Specification from the drop down list at the top and pick + client Bartel Leendert van der Waerden. Now check the Profile + checkbox and then click the Start Processing button. You should + now see a pop up window with the text "Error: Name too long!". + This window is a ZClientErrorDialog. + */ +\endcode + + +\section3 Troll Print 1.1 + +We'll now prepare release 1.1 of Troll Print. Start your favorite text +editor and follow these steps: + +\list +\i Uncomment the two lines that create a \l QLabel with the text + "\<b\>TROLL PRINT\</b\>" in \c printpanel.cpp. +\i Word-tidying: Replace "2-sided" by "Two-sided" in \c printpanel.cpp. +\i Replace "1.0" with "1.1" everywhere it occurs in \c mainwindow.cpp. +\i Update the copyright year to 1999-2000 in \c mainwindow.cpp. +\endlist + +(Of course the version number and copyright year would be consts or +#defines in a real application.) + +Once finished, run \l lupdate, then open \c tt3_pt.ts in \e {Qt +Linguist}. The following items are of special interest: + +\list +\i \c MainWindow + \list + \i Troll Print 1.0 - marked "(obs.)", obsolete + \i About Troll Print 1.0 - marked "(obs.)", obsolete + \i Troll Print 1.0. Copyright 1999 Macroshaft, Inc. - + marked "(obs.)", obsolete + \i Troll Print 1.1 - automatically translated as + "Troll Imprimir 1.1" + \i About Troll Print 1.1 - automatically translated as + "Troll Imprimir 1.1" + \i Troll Print 1.1. Copyright 1999-2000 Macroshaft, + Inc. - automatically translated as "Troll Imprimir 1.1. + Copyright 1999-2000 Macroshaft, Inc." + \endlist +\i \c PrintPanel + \list + \i 2-sided - marked "(obs.)", obsolete + \i \<b\>TROLL PRINT\</b\> - unmarked, i.e. untranslated + \i Two-sided - unmarked, i.e. untranslated. + \endlist +\endlist + +Notice that \l lupdate works hard behind the scenes to make revisions +easier, and it's pretty smart with numbers. + +Go over the translations in \c MainWindow and mark these as "done". +Translate "\<b\>TROLL PRINT\</b\>" as "\<b\>TROLL IMPRIMIR\</b\>". +When you're translating "Two-sided", press the \e {Guess Again} +button to translate "Two-sided", but change the "2" into "Dois". + +Save and quit, then run \l lrelease. The Portuguese version +should look like this: + +\img tt3_11_pt.png +\caption Tutorial 3 Screenshot, "Troll Imprimir 1.1", Portuguese version + +Choose \e{Ajuda|Sobre}, (\e{Help|About}), to see the about box + +\img tt3_11_about_pt.png +\caption Tutorial 3 Screenshot, About box, Portuguese version + +\index English Language +\index Translating Qt +\index Qt!Translating Qt + +If you choose \e {Ajuda|Sobre Qt}, (\e {Help|About Qt}), you'll get +an English dialog. Oops! Qt itself needs to be translated. See the +document \link i18n.html#qt-itself Internationalization with Qt +\endlink for details. + +Now set \c LANG=en to get the original English version: + +\img tt3_11_en.png +\caption Tutorial 3 Screenshot, "Troll Print 1.1", English version + +\section2 Summary + +These tutorials cover all that you need to know to prepare your Qt +applications for translation. + +At the beginning of a project add the translation source files to be +used to the project file and add calls to \l lupdate and \l lrelease to +the make file. + +During the project all the programmer must do is wrap any user-visible +text in \c tr() calls. They should also use the two argument form for +Ctrl key accelerators, or when asked by the translator for the cases +where the same text translates into two different forms in the same +context. The programmer should also include \e TRANSLATION comments to +help the translator navigate the application. |