Multilingual Application Development

in
Platforms:

Developing a multilingual application is rather simple with Symbian OS and this tutorial will show you to achieve this. Of course, it is always tempting to hardcode your strings. But with only a little effort you can have your application working in English and your native language - sorry for the Brits which do not need this ;-). A couple of web friends will probably help you adding extra translations in a second step.

Introduction

In our example, let's consider we will write an application that supports three languages:
-  English
-  French
-  German

The application is amazingly called MyApp. It might be running on any GUI environment, a few figures here and there are specific to UIQ but are not directly related to our discussion.

This tutorial mostly introduce the changes you have to make to this application to turn it into a true multilingual one. There are 5 steps:
-  identify all your strings and put them into specific language file
-  update your resources
-  update your source code so that it handle variable strings instead of hardcoded ones
-  update your MMP file to tell the resource compiler which language are supported
-  localize the name of the application
-  package the whole.

Step 1: Put your strings in a localisation file

The first step is to create three localised files, named MyApp.l01, MyApp.l02 and MyApp.l03, which will respectively describe my english, french and german strings. The 01, 02 and 03 figures are Symbian OS convention to identify a language. All the possible values are defined by the TLanguage enum found in e32std.h:

Language TLanguage Enum Code Language TLanguage Enum Code
UK English ELangEnglish 01 Catalan ELangCatalan 44
French ELangFrench 02 Croation ELangCroatian 45
German ELangGerman 03 Canadian English ELangCanadianEnglish 46
Spanish ELangSpanish 04 International English ELangInternationalEnglish 47
Italian ELangItalian 05 South African English ELangSouthAfricanEnglish 48
Swedish ELangSwedish 06 Estonian ELangEstonian 49
Danish ELangDanish 07 Farsi ELangFarsi 50
Norwegian ELangNorwegian 08 Canadian French ELangCanadianFrench 51
Finnish ELangFinnish 09 Gaelic ELangScotsGaelic 52
American ELangAmerican 10 Georgian ELangGeorgian 53
Swiss French ELangSwissFrench 11 Greek ELangGreek 54
Swiss German ELangSwissGerman 12 Cyprus Greek ELangCyprusGreek 55
Portuguese ELangPortuguese 13 Gujarati ELangGujarati 56
Turkish ELangTurkish 14 Hebrew ELangHebrew 57
Icelandic ELangIcelandic 15 Hindi ELangHindi 58
Russian ELangRussian 16 Indonesian ELangIndonesian 59
Hungarian ELangHungarian 17 Irish ELangIrish 60
Dutch ELangDutch 18 Swiss Italian ELangSwissItalian 61
Belgian Flemish ELangBelgianFlemish 19 Kannada ELangKannada 62
Australian English ELangAustralian 20 Kazakh ELangKazakh 63
Belgian French ELangBelgianFrench 21 Kmer ELangKhmer 64
Austrian German ELangAustrian 22 Korean ELangKorean 65
New Zealand English ELangNewZealand 23 Lao ELangLao 66
International French ELangInternationalFrench 24 Latvian ELangLatvian 67
Czech ELangCzech 25 Lithuanian ELangLithuanian 68
Slovak ELangSlovak 26 Macedonian ELangMacedonian 69
Polish ELangPolish 27 Malay ELangMalay 70
Slovenian ELangSlovenian 28 Malayalam ELangMalayalam 71
Taiwanese Chinese ELangTaiwanChinese 29 Marathi ELangMarathi 72
Hong Kong Chinese ELangHongKongChinese 30 Moldovian ELangMoldavian 73
PRC Chinese ELangPrcChinese 31 Mongolian ELangMongolian 74
Japanese ELangJapanese 32 Norwegian Nynorsk ELangNorwegianNynorsk 75
Thai ELangThai 33 Brazilian Portuguese ELangBrazilianPortuguese 76
Afrikaans ELangAfrikaans 34 Punjabi ELangPunjabi 77
Albanian ELangAlbanian 35 Romanian ELangRomanian 78
Amharic ELangAmharic 36 Serbian ELangSerbian 79
Arabic ELangArabic 37 Sinhalese ELangSinhalese 80
Armenian ELangArmenian 38 Somali ELangSomali 81
Tagalog ELangTagalog 39 International Spanish ELangInternationalSpanish 82
Belarussian ELangBelarussian 40 American Spanish ELangLatinAmericanSpanish 83
Bengali ELangBengali 41 Swahili ELangSwahili 84
Bulgarian ELangBulgarian 42 Finland Swedish ELangFinlandSwedish 85
Burmese ELangBurmese 43 Tamil ELangTamil 87
Telugu ELangTelugu 88
Tibetan ELangTibetan 89
Tigrinya ELangTigrinya 90
Cyprus Turkish ELangCyprusTurkish 91
Turkmen ELangTurkmen 92
Ukrainian ELangUkrainian 93
Urdu ELangUrdu 94
Vietnamese ELangVietnamese 96
Welsh ELangWelsh 97

// MyApp.l01
// English localisation
#define ELanguage   ELangEnglish  

// Localised strings
#define STRING_HOWAREYOU      "How are you ?"
#define STRING_APPLES         "You have %d apples."
#define STRING_EXIT           "Exit"

// MyApp.l02
// French localisation
#define ELanguage   ELangFrench

// Localised strings
#define STRING_HOWAREYOU      "Comment allez vous ?"
#define STRING_APPLES         "Vous avez %d pommes."
#define STRING_EXIT           "Sortir"

// MyApp.l3
// German localisation
#define ELanguage   ELangGerman

// Localised strings
#define STRING_HOWAREYOU      "Wie gehen Sie ?"
#define STRING_APPLES         "Sie haben %d Apfels."
#define STRING_EXIT           "Schliessen"

Then create a localisation file that will gather the three files above:

// MyApp.loc
// Localisation for MyApp

#ifdef LANGUAGE_01
#include "MyApp.l01"
#endif

#ifdef LANGUAGE_02
#include "MyApp.l02"
#endif

#ifdef LANGUAGE_03
#include "MyApp.l03"
#endif

The purpose of this .loc file is only to ease the inclusion of the proper language file in your .rss, so it is a pure convention to use and define it.

As far as I am concerned, I generally put all these files with my RSS file, in a dedicated directory called rsc. This is definitely not a mandatory requirement. Just think that these files are included so their path should be accessible from the MMP file. But this is another story we will discuss in step 4.

Step 2: Use localised strings in your menus and dialogs

Now that we have our localised strings, let's integrate them in our resource files so they can be taken into account. First, we have to include the .loc file at the beginning of our resource definitions:

// MyApp.rss
NAME HELL

#include <eikon.rh>
#include "MyApp.hrh"
#include "MyApp.loc"  // <<<< Here it is

RESOURCE RSS_SIGNATURE { }

RESOURCE TBUF { buf=""; }
...

Once this is done, we change the hardcoded strings in our objects by indirections to the localised ones. Ex:

//***************************************************************************
RESOURCE MENU_PANE r_myapp_menu
//***************************************************************************
{
 items=
 {
   MENU_ITEM { command=EMyAppHowAreYou;  txt=STRING_HOWAREYOU; },
   MENU_ITEM { command=EEikCmdExit;      txt=STRING_EXIT; }
 };
}

instead of:

//***************************************************************************
RESOURCE MENU_PANE r_myapp_menu
//***************************************************************************
{
 items=
 {
   MENU_ITEM { command=EMyAppHowAreYou;  txt="How are you?"; },
   MENU_ITEM { command=EEikCmdExit;      txt="Exit"; }
 };
}

That wasn't a big deal! This is enough if you only need to localise your menu. But if you intend to use localised strings in your code as well, then you also have to define a resource buffer to hold them. Simply add a TBUF resource declaration for each string you need to access from your code at the end of your .rss file:

/***************************************************************************
// STRINGS
//***************************************************************************
RESOURCE TBUF r_string_apple  { buf=STRING_APPLE;  }
RESOURCE TBUF r_string_thanks { buf=STRING_THANKS; }
...

Step 3: Use localised strings in your code

You should now be able to delete most of the _LIT() definitions in your code. Ex, no more:

myDes.Format(_L("You have %d apples"),num);

Use instead a format string read from the resource file. This is slightly more complex but CCoeEnv::AllocReadResourceLC() will do most of the job for you:

HBufC* formatBuf=CCoeEnv::Static()->AllocReadResourceLC(R_STRING_THANKS);
myDes.Format(formatBuf,num);
CleanupStack::PopAndDestroy(formatBuf);

This code allocates a HBufC descriptor and copy the R_STRING_APPLE strings into it. The descriptor is then used as a format template to include a numerical value. Depending on the language settings of your phone (and the num value!), the myDes descriptor contain "You have 3 apples.", "Vous avez 3 pommes." or "Sie haben 3 Apfels" (Note: I must apologize for this real dummy text but I only speak and write very limited German!).

Step 4: Update your MMP file

That's all as far the code is concerned. However, a small update is necessary in the MMP file to tell the resource compiler which language shall be used. Add a LANG statement with the code corresponding to each of the language you currently support:

TARGET        MyApp.app
TARGETTYPE    app
UID           0x100039CE 0x0EB00551

TARGETPATH    \system\apps\Myapp

// Language in which the application is translated
// (each supported language shall provide a MyApp.lxx file where
// xx is the code number of the language:
// 01 = english, 02 = french, 03 = german, etc... )
LANG        01 02 03

SOURCEPATH  ..\src
SOURCE      MyAppMain.cpp
SOURCE      MyAppDocument.cpp
SOURCE      MyAppUi.cpp
SOURCE      MyAppView.cpp
SOURCE      MyAppModel.cpp

SOURCEPATH  ..\rsc
RESOURCE    MyApp.rss

USERINCLUDE ..\inc
USERINCLUDE ..\rsc
...

Remember to include your .rss file in the compilation (with the RESOURCE statement) and to include the path to your localisation files as well (the second USERINCLUDE primitive).

Step 5: Localize the name of your application

The name of the application is by default the name of the .app file which cannot be localised. However,by creating an .aif file, you can specify localised name for your application. First, create or update the definition file as specified:

//MyAppAif.rss
#include <aiftool.rh>

RESOURCE AIF_DATA
{
 app_uid=0x0EB00551;
 num_icons=2;
 embeddability=KAppNotEmbeddable;
 newfile=KAppDoesNotSupportNewFile;

 caption_list=
 {
   CAPTION { code=ELangEnglish; caption="MyApp";  },
   CAPTION { code=ELangFrench;  caption="MonApp"; },
   CAPTION { code=ELangGerman;  caption="MeinApp";}
 };
}

The caption_list associates one different name to each language configuration. Now add the corresponding statement at the end of your .mmp if it is not already present:

AIF MyApp.aif . ..\aif\MyAppaif.rss
               c12 ..\aif\newlc42x35.bmp ..\aif\newlc42x35m.bmp
               ..\aif\newlc42x29.bmp ..\aif\newlc42x29m.bmp

This also customizes the logo that appears on the Launcher Menu to represent your application.

Step 6: Update your PKG file

Still reading ? Good, and you are now close to the end. But now is the time to ask you a question reagarding the packaging and the installation of the languages files. Do you want to:
-  install all the languages silently on the phone (this may waste some space for complex/big applications but do not bother the user with a language popup)
-  ask the user which language he wants to install ? (this uses less space on the disk but adds a step in the installation process)

Let's take the first option first. As we don't want to bother the user with the language popup dialog, then we will install a resource file corresponding to each language we support and we rely on the operating system for the language selection. By default, these resource files have the extension .rXX where XX is the language code and they are located in the

\epoc32\data\z\system\apps\MyApp\

directory. We have to list all them in our .pkg and install them in our application directory:

;
; Installation file for MyApp example application
; "Silent" version: no language popup
;
; UID is the app's UID
;
#{"MyApp"},(0x0EB00551),1,0,0

; Target is UIQ 2.0 devices.
(0x101F617B), 2, 0, 0, {"UIQ20ProductID"}

;
; Main App
;
"\epoc32\release\armi\urel\MyApp.app"   -  "!:\system\apps\MyApp\MyApp.app"
"\epoc32\data\z\system\apps\MyApp\MyApp.r01"
-  "!:\system\apps\MyApp\MyApp.r01"
"\epoc32\data\z\system\apps\MyApp\MyApp.r02"
-  "!:\system\apps\MyApp\MyApp.r02"
"\epoc32\data\z\system\apps\MyApp\MyApp.r03"
-  "!:\system\apps\MyApp\MyApp.r03"
"\epoc32\data\z\system\apps\MyApp\MyApp.aif"   -"!:\system\apps\MyApp\MyApp.aif"

You may notice that, despite the fact we are writing a multilingual application, we do not specify any language in this .pkg. This is why the user won't be asked. And the magic there is that your application will appear in English for a English user, in French for a French user and in German for a German user. User of other countries will see what Symbian OS think is the most appropriate language according to their locale settings (which is generally English). And if you switch your phone language, the application will automatically switc has well! One of the issue with this method is that ou cannot completely localize the name of the application as it will be displayed by the installer.

The other alternative is to display a language popup at install time, and only install the requested language. No change is required in your code, just tweak a few lines in your .pkg:

;
; Installation file for MyApp example application
; Standard version: language popup
;
;Languages
&EN,FR,GE

; UID is the app's UID
;
#{"MyApp","MonApp","MeinApp"},(0x0EB00551),1,0,0

; Target is UIQ 2.0 devices.
(0x101F617B), 2, 0, 0, {"UIQ20ProductID", "UIQ20ProductID", "UIQ20ProductID"}

;
; Main App
;
"\epoc32\release\armi\urel\MyApp.app"                     -  "!:\system\apps\MyApp\MyApp.app"
{
"\epoc32\data\z\system\apps\MyApp\MyApp.r01"
"\epoc32\data\z\system\apps\MyApp\MyApp.r02"
"\epoc32\data\z\system\apps\MyApp\MyApp.r03"
}
-  "!:\system\apps\MyApp\MyApp.rsc"
"\epoc32\data\z\system\apps\MyApp\MyApp.aif"   -"!:\system\apps\MyApp\MyApp.aif"

This .pkg generates a .sis file that will behave slightly differently at installation:
-  the application has the name that is localised even in the installer (here "MyApp", "MonApp" or "MeinApp".
-  a popup will be shown and the user will be asked to select a language
-  only one of the three .rXX file will be installed on the phone and it will be renamed as .rsc.
-  after installation, the application will always appear in this language, no matter of the phone language settings.

Related Links

If you are interested in localizong your own application, the following links may be of interest for you:
-  The Nokia language example in the directory Series60Ex\Language of your Series 60 SDK
-  Localization by Ariel of Giant Steps, Ltd
-  How to make a multilingual application installerby SavaaZ
-  The Localisation example on Sendo Developer site (requires a registration).


amazing

Hi Eric, It's pretty amazing that this article of your looks pretty much the same than mine, which I made few weeks ago. Although there is no links to my article anywhere and thats why I'm so amazed that this looks so much the same. Nice work though and very useful article to everybody who want to localize his/her app.

My two articles are in symbian.louhos.com/localization.php and symbian.louhos.com/resource.php

btw. This site has been very helpful!

> amazing

Hi,

I couldn't add links to your articles as I did not know them before your post! I assume most similarities are due to the fact that we both inherits from the Language exemple found in the Nokia Series 60 SDKand AFAIK there aren't thousands of other methods to write multilingual applications in Symbian OS.

BTW what is the hypnodonkey ? ;)

Cheers, Eric

> amazing

Hmm, reminds me my aritcle as well (http://www.newlc.com/article.php3?id_article=443)

> amazing

When you set up an app this way, what language does it appear in when run on the Symbian emulator? Or does the emulator always use a default language? Thanks, Dan

> Multilingual Application Development

When I try to make the SIS file in Symbian 80, I get error ""Expected quoted string read ,". I have to remove the commas between language files, like this: "C:\Symbian\7.0s\S80_DP2_0_SDK\Epoc32\release\armi\urel\MDMNotifier.rsc" "C:\Symbian\7.0s\S80_DP2_0_SDK\Epoc32\release\armi\urel\MDMNotifier.r09" "C:\Symbian\7.0s\S80_DP2_0_SDK\Epoc32\release\armi\urel\MDMNotifier.r49" -"c:\system\apps\MDM\MDM.rsc"

> Multilingual Application Development

Hi,

I am trying to follow this article however, the resource file does not compile. I cannot even see any error, just that when I try to make the SIS package, it cannot find the .rsc file.

As soon as I remove localization code, the app works fine.

If anyone can help it would be great.

Thanks!

> Multilingual Application Development

Hi Eric, Very good article. But All the articles related to this subjects, ignores, HLP file creation for multiple languages. Can you please throw some light on this issue as how we can localize HLP files and add to the installer.

thanks

regards

rapsage

> Multilingual Application Development

Thanks :-) Actually I never had to deal with HLP files so I don't know how to do this. If someone has the answer and can write a short memo.....

> Multilingual Application Development

in order to have multiple localized help files you only have to name them .h01, .h02, etc. in the system/help folder... the system will take care of displaying the right one depending on the phone language

> Multilingual Application Development

Hi Guys,

There is a simpler way to localize your software. It is called "StringDB". It is a binary resource file for strings that is generated directly from string tables in MS Excel sheets. It is simple to use and highly flexible for different platforms.

By using StringDB concept you don't need any other resource files for strings. No need to manipulate strings manually. And no need to recompile to change language package of the software.

You can find the trial software and documentation on the web site www.swbox.com.

Mike

> Multilingual Application Development

just for the sake of a correct example: in german "How are you?" is "Wie geht es ihnen?" and "apples" is not Apfels, but "Äpfel"....

but i like the rest of the tutorial :-)

> Multilingual Application Development

hey this StringDB is a better approach i think,

i just used 3 functions, and multi-language system is done! using MS Excel is also a plus fo rme.

pew, now i see that those long struggles for multi-language applications was a waste of time.

> Multilingual Application Development related to PRC

Hello,

Can you tell me in detail what is PRC code. What does PRC stand for? and How to creat it? Has it related to Unicode for the font?

Thanks your help. Best regards,

Sochan.

Re: > Multilingual Application Development related to PRC

HI,

PRC stands for People Republic of China

> Multilingual Application Development

i m getting error while creating the sis file, Error is :

Processing Localization.pkg... Localization.pkg(23) : error: Expected quoted string read , Localization.pkg(23) : error: unexpected text

My pkg file is :

; ; Installation file for $$Root$$ application ; ;Languages &EN, ZH ; ; UID is the app's UID ; #"Localization", "Localization",(0x04F141C6),1,0,0 ; ;Supports Series 60 v 2.0 ;This line indicates that this installation is for the Series 60 platform v2.0 ;This line must appear _exactly_ as shown below in the sis file ;If this line is missing or incorrect, the sis file will not be able ;to be installed on Series 60 v2.0 platforms (0x101F7960), 0, 0, 0, "Series60ProductID", "Series60ProductID" ; ; Four files to install ; "C:\Symbian\7.0s\Series60_v21\Epoc32\release\armi\urel\Localization.app" -"!:\system\apps\Localization\Localization.app" "C:\Symbian\7.0s\Series60_v21\Epoc32\data\z\system\apps\Localization\Localization.rsc" , //THIS IS CAUSING ERROR "C:\Symbian\7.0s\Series60_v21\Epoc32\data\z\system\apps\Localization\Localization.r31" -"!:\system\apps\Localization\Localization.rsc" "C:\Symbian\7.0s\Series60_v21\Epoc32\data\z\system\apps\Localization\Localization_caption.rsc" -"!:\system\apps\Localization\Localization_caption.rsc" "C:\Symbian\7.0s\Series60_v21\Epoc32\data\z\system\apps\Localization\Localization.aif" -"!:\system\apps\Localization\Localization.aif"

plz let me know wht i m doing wrong.