Internationalization

Translating and localizing the application

Make sure all source files are commited/archived somewhere else ,before starting to work with the translation commands, because the translation commands perform mass file changes, which might be hard to recover from if something goes wrong.

Overview

Applications based on Dynamics Mobile SDK can be developed with the idea of being used by users speaking various languages and using the apps in various countries.

In this regard, the Dynamics Mobile SDK provides tools for the developer to localize and translate the app.

Localization

The localization concept stands for implementing the app so that it can behave in different way depending on the region it is used. The reason for this is that different countries and regions might have different requirements and regulations regarding the business processes supported by the apps.

From a development perspective , the developer must develop the app so that it can behave in different way ( e.g. executing different business logic ) depending on some conditions. Such conditions can be :

  • detecting the current location of the device via call to DeviceService.location.get

  • detecting the current region by asking the user - e.g. using some sort of settings provided by the user

  • performing AJAX call to remote services

Translation

The translation of the user interface is important concept and there is a special set of tools allowing the developers to make so that their app can run in different languages.

This refers to all of the UI elements displayed on the screen.

A basic concept in the translation process is the use of a translation resource. A translation resource is a special identifier used within the htmls and ts files across the app, which is replaced with properly translated string during the app compilation process.

Using translation resources in html files

Lets assume we have the following html in a view:

<div class="page-content">
<span>Hello</span>
</div>

The given html will produce a simple Hello text on the screen of the app ,when compiled. This is completely fine, but this approach does not allows us to run the app in different languages. So if we want to deploy the app for usage from French speaking users, we either need to maintain a different version for French speaking users or better use a translation resource. So our translatable html view must look like:

<div class="page-content">
<span>{#lblHello#}</span>
</div>

So we are replacing the Hello text with {#lblHello#}. The {#lblHello#} text is a translation resource. Every text which starts with {# and ends with #} is a translation resource. So when we build the app, the compiler will detect the {#lblHello#} text and will try to find the given translation resource in our translation files. In our app we can have a multiple translation files under the /Translations folder - one file per language.

So for example our Translations folder may look like this:

-src
+Business Objects
+Views
-Translations
-en.lang.json
-fr.lang.json

So we have two translation files:

  • en.lang.json- contains all translation resources for english

  • fr.lang.json - contains all translation resources for french

Our en.lang.json file may look like this:

{
"resources":[
{
"name":"lblHello",
"text":"Hello"
},
{
"name":"btnYes",
"text":"Yes"
}
...
]
}

So it contains array with all of the translation resources used in our app. The name is the actual translation identifier and the text property contains the text of the resource in the given language - english in this case

Our fr.lang.json file will look like this:

{
"resources":[
{
"name":"lblHello",
"text":"Bonjour"
},
{
"name":"btnYes",
"text":"Oui"
}
...
]
}

When the app is compiled, the compiler will replace the translation identifier with the actual text from the language file, which will automatically translate our app to the given target language.

Using translation resources in typescript files

We can use the same technique to translate strings in typescript files. So for example:

export class MyView {
amount: ko.Observable<number>();
...
async validate(): Promise<boolean> {
if(!amount()){
this.UserInterfaceService.showError('{#msgAmountIsRequired#}');
return false;
}
return true;
}
}

The given code shows error message on line #6. The message text is actually a translation resource - msgAmountIsRequired. So, we need to define the new translation resource in the translation files.

//en.lang.json
{
"resources":[
{
"name":"lblHello",
"text":"Hello"
},
{
"name":"btnYes",
"text":"Yes"
},
{
"name":"msgAmountIsRequired",
"text":"Please provide value in the amount field"
}
]
}

//fr.lagg.json
{
"resources":[
{
"name":"lblHello",
"text":"Bonjour"
},
{
"name":"btnYes",
"text":"Oui"
}
,
{
"name":"msgAmountIsRequired",
"text":"Veuillez fournir une valeur dans le champ du montant"
}
]
}

Exporting translation resources

Sometimes the developer needs to use third-party services to get quality translations of the resources. In this case it will not be appropriate to send the resources to the translation agency in JSON format. We can export the resources in convenient CSV file, which can be then open and edited with Excel or other spreadsheet software.

We can use the following command line tools for this purpose:

/>cd myapp
/myapp>npm run i18n -- export --from en --to fr --file "c:\myapp\english-french.csv"

The command will produce the following csv file

Item

en

fr

lblHello

Hello

Bonjour

btnYes

Yes

Oui

msgAmountIsRequired

Please provide value in the amount field

Veuillez fournir une valeur dans le champ du montant

If there are translation resources in any of the files ( fr or en ), which are not available in both of the files , they will still be added to the CSV file. We can now send the CSV file to the translation service and ask them to provide translations to french for each of the english texts.

Importing translation resources

Once the CSV file is sent to the translation agency, the agency may provide translations under the column of the target language and send back the CSV file.

The development team may import the CSV back into the corresponding language file.

Let us assume , we have received the following CSV file from the translation agency:

Item

en

fr

lblHello

Hello

Bonjour

btnYes

Yes

Oui

msgAmountIsRequired

Please provide value in the amount field

Veuillez fournir une valeur dans le champ du montant

Let us also assume that the CSV file is saved under the following file path on the development machine:

c:\myapp\english-french.csv

We can use the following command to import the CSV into fr.lang.json file:

/>cd myapp
/myapp>npm run i18n -- import --file "c:\myapp\english-french.csv" --to fr --col 2

The command will initiate importing of translation resources from the CSV file into myapp/src/Translations/fr.lang.json

The command will automatically detect if fr.lang.json already exists and will only override the resources available in the CSV and will preserve the already existing resources.

Other commands

The i18n script contains several other useful commands

Translate

The command scans all source files (*.html, *.ts) for non-translated strings and replaces them with translation resources.

/>cd myapp
/myapp>npm run i18n -- translate

The command will scan all files and will dump in the terminal the resources, which will be translated.

So, the output will contain the list of the files, which will be affected , the strings to be replaced in each file and the total number of files and resources to be changed. Not that the command will not actually change the files, but only will report them in the terminal window.

So in the upper example, the command is reporting that in SysInfo.html, it will affect 9 resources. For example the string "Run DMS- SPT1" will be replaced with resource identifier txtRunDMSSPT1.

You need to review the potential changes and then run the command in the following way to actually commit the changes:

/>cd myapp
/myapp>npm run i18n -- translate --save true

Extract

The translate command is using an algorithm, which sometimes may happen to miss certain strings, which has to be translated. It also may happen that the algorithm may suggest for translation character sequences, which are not supposed to be translated. The developer needs to use the translate command, without the --save switch first. Once the developer is pleased with the suggested changes, the developer needs to run the translate command with --save true switch.

The command checks all source files (*.html, *.ts) for existing translation resources {#xxxxxx#} and then adds them into the given language json file.

/>cd myapp
/myapp>npm run i18n -- extract --to fr

The example will extract all language resources from the source files and will add them to the french translation file - /src/Translations/fr.lang.json. It will create the file, if the file does not exists and will preserve any existing identifiers. You can use the --override true switch to force the command to override the existing translation file.

You can run the translate and then the extract com

Available translation commands

Command

Description

npm run i18n -- export

Exports the translation resources from one language file to CSV file

npm run i18n -- import

Imports translation resources from CSV file to specific language file

npm run i18n -- translate

Replaces all "strings" into *.ts and *.html files with translation resource identifiers

npm run i18n -- extract

Detects translation resource identifiers in the source files and adds them to specific language file.

npm run i18n -- --help

Displays help information for the supported commands