summaryrefslogtreecommitdiffstats
path: root/tools/linguist/book/linguist-programmer.leaf
diff options
context:
space:
mode:
authorTimothy Pearson <[email protected]>2011-11-08 12:31:36 -0600
committerTimothy Pearson <[email protected]>2011-11-08 12:31:36 -0600
commitd796c9dd933ab96ec83b9a634feedd5d32e1ba3f (patch)
tree6e3dcca4f77e20ec8966c666aac7c35bd4704053 /tools/linguist/book/linguist-programmer.leaf
downloadtqt3-d796c9dd933ab96ec83b9a634feedd5d32e1ba3f.tar.gz
tqt3-d796c9dd933ab96ec83b9a634feedd5d32e1ba3f.zip
Test conversion to TQt3 from Qt3 8c6fc1f8e35fd264dd01c582ca5e7549b32ab731
Diffstat (limited to 'tools/linguist/book/linguist-programmer.leaf')
-rw-r--r--tools/linguist/book/linguist-programmer.leaf1145
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 000000000..d74fdf1fe
--- /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 retquired. 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 retquires 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 retquires translating retquires context to help
+the translator identify where in the program the text occurs. In the
+case of multiple identical texts that retquire different translations,
+the translator also retquires 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 retquired 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 Retquire 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 tquit()
+\printline tquit()
+\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:
+"\&#xf8;". 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 tquit()
+\printline tquit()
+\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 tquickest 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 retquires 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 tquit
+\printline tquit
+\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 tquit. 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 tquit, 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.