PhAB has builtin support for applications that need to be translated into other languages. By keeping a few design considerations in mind, and then following a few simple steps, your application can very easily be translated into other languages without the need to recompile or rebuild your application:
It's that simple.
This section provides a few design considerations to assist you in creating a language-independent application. You should keep these ideas in mind as you are designing and implementing your application, since modifying the application after it's complete is more difficult.
Typically, when you design an application, you lay out the window using widgets that have the default application text already preset. For example, if you had a Done button at the bottom of a dialog window, the button itself would be only large enough to hold the text string "Done". You would also place the Done button based on its current size. This works well in an application that doesn't require translation, but causes many problems for a language-independent application. What would happen if the translated text were 12 characters instead of the default of 4 characters?
or
For example, these buttons are too small to accommodate translated text:
The solution is simple. Make the button larger to accommodate longer translated text strings. Here's an example:
In addition to making text-based widgets wider to accommodate translated text, you should give some thought to the justification of text, based on the widget's usage. For example, in a simple text entry field, it's quite common to place a label to the left side of the field. If you make the label wider to allow for translation, the label itself moves to the far left:
This problem is easily solved by setting the label's horizontal alignment to be right-justified. This allows for longer translated text strings, and still keeps a tight alignment with the text entry field:
Another common labeling method is to place a label centered above or within the border of a box. Usually the text is centered by placing it in the desired position based on its current text:
When the text is later translated, it's either too short or too long, and the box label looks lopsided. The simple solution is to make the box title much wider than necessary, and set the horizontal alignment to be centered.
There are probably many other cases similar to this but the important point is to think about how the translated text will effect the look of the application. A lot of aesthetics can be maintained simply by making text-based widgets wider and setting an appropriate justification.
The fonts for some languages, such as Japanese or Chinese, are only readable at large point sizes. For these fonts, the minimum size may be 14 points or even larger. If you've designed your entire application using a 10 point Helvetica font you'll have lots of problems when all your text-based widgets are stretched 4 or more pixels taller to accommodate the larger fonts. If your application needs to be translated to other languages, look into the font requirements before you begin, and use this minimum font size in the default language built into the application.
If you really want to use the smaller font sizes for your default application text, you can borrow a tip from the previous section. You can make the height of widget larger and set the vertical alignment to center. However, this may not work well for text input fields, and you should keep this consideration in mind.
Another major area for consideration is with informational, warning, error or any textual messages that are displayed in popup dialog windows or other points within the application. Examples could be PtAskQuestion() or the PtMessage widget. The most common way to handle text messages is to embed the text strings in the application code. For example:
PtAskQuestion( ABW_base, NULL, "File has changed. Save it?", "helv14", "&Yes", "&No", "&Cancel", 1 );
While this is quick to code, it's impossible to translate without rewriting the application code, recompiling, and so on. Essentially, you need to create a complete new version of the application for each language supported. A much better method is to take advantage of PhAB's widget databases. Using a widget database, you can put all your text messages in a single (or multiple) database and give each message a unique name. To retrieve the text at runtime, call ApGetTextRes() (see the Photon Library Reference for details). In the above example, it would become:
PtAskQuestion( ABW_base, NULL, ApGetTextRes( textdb, "@msg001"), "helv14", ApGetTextRes( textdb, "@msgyes" ), ApGetTextRes( textdb, "@msgno"), ApGetTextRes( textdb, "@msgcancel", 1 );
This method allows the application to have no predefined text-based messages within it, and it can be easily translated. In addition, because the text strings are put into a widget database, PhAB automatically takes care of including the message texts when it generates the application's text string database. This is more convenient than simply using an external text file and designing some other method for translating this file.
By default, PhAB ignores widgets that have no instance name or have the instance set to the class name. This means if you place a label within a window and change the text to something appropriate, PhAB skips this widget when it generates code for your application. This is because PhAB assumes the label is constant and the application doesn't require access to it. However, when it comes to translating your application to another language, this label becomes very important.
To differentiate between widgets that are important for translation but not for code generation, PhAB recognizes a special character when placed in the first position of the instance name. This special character is the @ character. This means you can give a label the instance name of @label1, and PhAB will recognize this label when generating the text language database, but skip over it when generating code.
This sounds fine, except PhAB also requires that all instance names be unique. This rule must be adhered to so that PhAB knows which text string to replace at run time. Unfortunately, dreaming up potentially hundreds of unique instance names that you don't really care about can be a lot of work. To simplify this task, PhAB lets you specify a single @ character for the instance name, and PhAB appends an internal sequence number to the end. This eliminates the need to keep track of all constant text strings that require instance names just for translation.
If you want to group translation text strings (say, by module), you can give them all the same instance name, and PhAB will append a sequence number to make the name unique. For example, if you assign the name @base to several widgets, PhAB generates @base, @base0, @base1, ... as instance names.
Sometimes it's necessary to design an application to be bilingual. This means two different languages are displayed in every text string. While this can be done, it's usually difficult for the user to read and understand.
PhAB allows you to use another approach. You can create the application in one language and provide the ability to flip to the other language within application control. This is done via a PhAB API function named ApSetTranslation(). This function (which is described in the Photon Library Reference) changes the current translation file for the application immediately, such that all future dialogs, windows, and so on are drawn using the new translation file.
Any existing modules and widgets aren't translated, only new ones. If you want immediate feedback, you need to recreate the modules. This is easy for dialogs, but more difficult for the base window; remember that destroying the base window exits the application. One way to translate the contents of the base window is to put them in a picture module, which can be recreated. |
If you have several applications to translate, you can reduce the work by sharing the common text strings and translating them separately. To do this:
This is the easy part. The most important aspect to this step is to know when to generate the text string database. Ideally, you want to do this when all application development is complete. This is because the run-time translation mechanism is hinged on the widget's instance name. If you generate your database mid-way through the development and do the translations, it's quite likely that a lot of widgets will be changed or deleted, and translations may be deleted or the time wasted.
One exception to this would be bilingual applications. In this case, you might want to generate and translate the application continuously so that the application's translations can be tested throughout the development.
To generate an application's language database:
The database has now been generated and is ready for use with the PhAB Language Editor. The name of the database is app.ldb, where app is the name of the executable file for the application (which is typically the same as the name of the application, unless you've used the Save As command to rename the application). The language database is placed in the application's directory (where the abapp.dfn file is found).
After the database has been generated, you can use PhAB's Language Editor to translate the default text strings to another language. The Language Editor is designed to work both as a stand-alone application that you can distribute with your application, or as an integrated part of PhAB itself.
PhAB Language Editor.
When you are developing an application within PhAB, you can run the Language Editor using the current application's language database quite easily:
This starts the Language Editor using the current application's language database. At this point, you can proceed to create a new translation file or edit an existing one.
If you plan to allow your application to be translated at a customer site, you'll need to include the following files with your application:
The languages.def file must be in the same directory as the phablang editor. |
To start at the client site, you can:
or
Once phablang is started:
to bring up the file selector.
To create a new translation file:
Language Selection dialog.
The Language Selection dialog closes, and you should now see the newly created translation file in the list of available translations.
To edit a translation file in the Translations list:
The Text Translation Editor dialog appears. This editor displays all the text strings available for translation in the current language database.
To translate a text string:
|
Repeat the above steps for all the text strings you need to translate. When you're finished, click on the Save & Close button.
The clipboard buttons aren't implemented at this time. |
One problem with translating an application is that the hotkey assignments no longer match up if the translated string doesn't include the accelerator key value. For this reason, PhAB adds the accelerator key strings to the language database too.
When translating the text string, the translator can also change the accelerator key. If the key used in the hotkey isn't a function key (i.e. the key code is less than 0xF000), PhAB automatically changes the hotkey to match the accelerator key.
For example, suppose your application has a button labeled Cancel. You'd set the button's Pt_ARG_ACCEL_KEY to be C, and arrange for Alt -C to invoke Pt_CB_HOTKEY.
When you generate the language database, you'll find that it includes the button's label and its accelerator key. If you translate the application into French, the button's label would become Annuler, so the hotkey Alt -C is no longer appropriate. Just translate the button's Pt_ARG_ACCEL_KEY to be A, and the hotkey automatically becomes Alt -A when you run the application in French.
You'll need to make sure there are no duplicate accelerator keys. If it does happen by accident, only the first key defined is accepted. |
If you use the Photon Helpviewer for your application help and you plan on providing multiple language help files for your application, the translator can also translate the help topic paths to point to the correct positions within the corresponding help files.
After the language database is fully translated, the last step is to run the application.
When you create the translation files, they're placed in the same directory as your application's abapp.dfn file. You can think of these as the working versions of the files. When you run your application from PhAB, these are the versions you'll use.
When you run your application outside of PhAB, it looks for the translation files as follows:
dir:dir:dir:dir
Unlike the PATH environment variable, the current directory must be indicated by a period, not a space. A space indicates the directory where the executable is.
You can think of these as the production versions of the translation files.
In order for the PhAB API to know which translation file you want to use, you must set the ABLANG environment variable to one of the values below:
Language: | Value: |
---|---|
Belgian French | fr_BE |
Canadian English | en_CA |
Canadian French | fr_CA |
Danish | da_DK |
Dutch | nl_NL |
French | fr_FR |
German | de_DE |
Italian | it_IT |
Japanese | ja_JP |
Norwegian | no_NO |
Polish | pl_PL |
Portuguese | pt_PT |
Slovak | sk_SK |
Spanish | es_ES |
Swedish | se_SE |
Swiss French | fr_CH |
Swiss German | de_CH |
UK English | en_GB |
USA English | en_US |
This list is current at the time this document was
written, but may have since been updated.
For the latest version, see the file:
/qnx4/phtk/appbuilder/languages.def |
For example, to run an application in German (as spoken in Germany), you would do the following:
$ export ABLANG=de_DE $ myapplication
The application looks for the best match.
For example, if the language extension specified is
fr_CA, the search is as follows:
If no translation is found, the original text in the application is used. |
The export command could be put in the user's login profile so that the application will run in each user's preferred language. For more information, see the section "PhAB multilingual applications" in the Unicode Multilingual Support chapter of the Installation & Configuration guide.
When you ship your application to the customer site, you must make sure to include the translation files in your distribution list. For example, if your application is named myapp, and you have translation files for French and German, you would need to include the myapp.fr_FR and myapp.de_DE files with the application. These files must be located:
dir:dir:dir:dir
Unlike the PATH environment variable, the current directory must be indicated by a period, not a space. A space indicates the directory where the executable is.
If you want each customer to be able to translate the application, you'll also need to distribute:
The language database and the translation files that the customer creates should be in: