VGDD:MultiLanguage

From VirtualFabWiki
Jump to: navigation, search

Multi-Language Support

What is it

When designing GUIs for devices that have to be used in different countries two different approaches can be adopted:

  • Build different firmware binaries, one for each language (a nightmare)
  • Have a centralized Strings "Pool" with all the needed translated strings, and display the correct one for the (user) selected language.

VGDD supports the second approach.

Enabling the Multi-Language Support slightly changes both the Designer (VGDD itself) and the generated code.

By generating code that embeds all the translated strings, a waste of precious flash happens indeed, but the benefits of having a single version for the firmware greatly compensates it. Not to mention that strings occupy far less storage than any bitmap: we are talking about GUI development!

How to enable it

In Project Settings, the new Multi-Language Settings Panel is available:

Multi-Language Settings Panel

To enable Multi-Language support, just set Number of Translations to any non-zero number. Setting it to 0 disables support.

Notice: main application's language is #0, then you can define one or more translations. Setting it to 1 means having 2 languages available: the main (reference) and one translated text for each string.

How to define translated strings

Once enabled, the Multi-Language support changes the behaviour of text editing for any Widget that has a Text property. When entering text, by clicking on the down arrow on the right, the new Multi-Language String editor appears:

Multi-Language String Editor

Here you can :

  • type in the default (reference) text and the translated strings, by double-clicking on the fields.
  • or choose an existing string from the pool, by clicking on the String# link

In the latter case, the String Pool appears, with all the strings and relative translations. To select one of them, double click on the row header.

Notice: you are not forced to translate each string used in your GUI: if a string doesn't need to be translated (i.e. the word "byte") then simply leave the translations empty: the VGDDString() function (see below) will pick up the default (reference) string for any NULL translated string.

Strings Pool

You can edit translated strings globally by opening the Strings Pool in Project Settings and clicking on Edit Strings Pool.

Strings Pool

You can modify strings by double clicking on their fields.

To delete an existing string, select the row by clicking on the row header and then press the CTRL-D key. Notice that by deleting a referenced (used) string ID, you'll most likely break your code.

Export and Re-Import as CSV

Strings can be exported as Comma Separated Values to be edited externally (i.e. by an external translation service) in the form of a spreadsheet, and can be subsequently re-imported to update the project.

The Export as CSV and Import from CSV buttons serve at this purpose.

Editing with a spreadsheet

Changing displayed language

In Project Settings, set the Active Language to any of the available translations. All the displayed texts in the designer will be in the chosen language.

Code Generation

When Multi-Language Support is active, an additional C module will be added to your project:

VGDD_<ProjectName>_StringsPool.c 

It contains the global variable used to select the active language to display:

VGDDActiveLanguage

Setting it to 0 displays the default (reference) text, while setting it to a different number displays the translated text.

It also contains the function used to pick-up the correct string from the pool:

VGDDString()

In generated code all widget's texts in the xxCreate() calls are replaced with this function and the correct String ID.

This is an example for a StaticText:

pScreen1_StaticTextEx1 = StExCreate(ID_Screen1_StaticTextEx1,60,76,209,129,STEX_DRAW|STEX_NOPANEL,(XCHAR*)VGDDString(0),GOLScheme_Default);

Font to use

Being MultiLanguage-enabled, your VGDD project will likely need the MultiByte (UniCode) chars support, that can be enabled in Project Settings.

Although VGDD's Strings Pool supports different fonts for different strings, to support foreign languages special characters the chosen font must support all of them at once, because the same object (a button) must be displayed in each of the enabled languages at runtime.

In particular, to support Chinese Language along with western ones, you have to use a Chinese font and it can be hard finding one that also has all of the western special characters, like the Italian accented vowels (à,è,ì,ò,ù), German ones (ä,ö,ü,ß,etc.) and French ones (â,ç,ê,î, etc.)

I found this one http://freedesktop.org/wiki/Software/CJKUnifonts/Download/ which seems to satisfy the minimum requirements for Chinese+Western characters.

SmartCharSet

This VGDD feature scans your project for characters used in your strings, and automatically builds a suitable font filter to include only the used characters.

This ensures that the font binary image won't fill up your flash memory.

Therefore, enabling SmartCharSet for the multilanguage font used in your application is strongly suggested.

String Translation

When using filtered fonts (i.e. SmartCharSet) the character sequence used by the Graphics Library to display characters from the filtered font is not ASCII anymore. So for example the code for 'A' character isn't 65, but something else, depending on which characters has been included in the final font table.

The first character in the font will take code 0x20 (32 decimal) and so forth.

This is completely transparent to the application as long as you use constant strings for your widgets: they are translated by VGDD during CodeGen and the correct character codes are put into the used constants.

But if your application needs to change widget's texts at runtime, then a translation is needed.

The filtered font character codes are stored in a constant whose name is <FontName>_FilterTable, which can be used to translate strings from ASCII to the correct values before feeding them to the Graphics Library to change widget's text.

Here it is a suitable routine which does the job:

// -------------------------------------------------------------------------------------
// Function FilteredFontTranslate
// -------------------------------------------------------------------------------------
// For strings that use a filtered font, this function translates an ASCII string to 
// the correct sequence of characters, according to the FilterTable definition
// Example:  FilteredFontTranslate("This is an ASCII String", BufTo, TahomaRegular68_FilterTable, sizeof(TahomaRegular68_FilterTable));

void FilteredFontTranslate(char *BufFrom, char *BufTo, const uint16_t *FilterTable, int FilterTableSize) {
   unsigned char c;
   char i;
   while ((c = *BufFrom)) {
      *BufTo = 0x20;
      for (i = 0; i<FilterTableSize; i++) {
         if (*(FilterTable + i) == c) {
            *BufTo = i + 0x20;
            break;
         }
      }
      BufFrom++;
      BufTo++;
   }
   *BufTo = 0x00;
}

Use strings in code

When Multi-Language support is enabled and you need to assign translated text to Widgets during runtime, VGDD comes to help supplying the VGDDString() function.

It takes the STRING_ID as input and returns a pointer to the translated string from the Strings Pool using the current active language (VGDDActiveLanguage global variable).

Example of usage:

StSetText((STATICTEXT *)GOLFindObject(ID_Summary_StaticText1), VGDDString(4));

in StringsPool.h there are #defines to the defined strings so you can have a more mnemonic

StSetText((STATICTEXT *)GOLFindObject(ID_Summary_StaticText1), STRING_SUMMARY);