Editor: Today we have a guest post from Martin Green. Martin spent nearly a decade repairing marine navigational equipment on “Lakers” and “Salties”, such as RADAR, Loran C, gyrocompasses, and early SatNav, followed by twenty-five years as a contract Enterprise software developer for governments, banks, and major corporations before coming to mobile and BlackBerry 10 Native development in early 2013. He is the owner of arsMOBILIS and the developer of multiFEED, an RSS/Atom reader app available in BlackBerry World.

If you have built (or are building) your BlackBerry 10 Native Cascades apps with internationalization in mind then you likely have code peppered with QML qsTr() calls and C++ tr() macros. When your app starts up the text wrapped in qsTr() or tr() is substituted with the localized text for the device locale and language (if defined, otherwise default translation is used). This works fine unless you change the language setting on your device while your app is running. Unless you take steps to propagate the language change through your live app, the text displayed in your UI will not match the new device language setting until the page is reloaded or your app is restarted. QML provides for this “live translation” with the Retranslate class which can be used with qsTr() to update translations as soon the device language setting is changed:

In this example label01 will have its text attribute live translated so that it is updated as soon as the device language is changed. On the other hand label02 will only have its text translated when the app is first started and subsequent language changes while the app is running will not update it.

Using the Retranslate class with QML makes live translation as simple as adding a small amount of code right after every use of qsTr(), but C++ provides no such convenience. To implement live translation in C++ code it is necessary to call the setXXX() slot for a string attribute with the tr() macro once to do the initial translation then connect the setXXX() slot to a LocaleHandler instance which emits a signal every time the language (or locale) changes. This is complicated by the fact that the LocaleHandler knows that the language has changed, but it doesn’t know which text key to supply to the slots it is attached to so we have to attach the LocaleHandler signal to an intermediary slot which knows what translation key to use for that attribute and which then emits another signal with the key as a parameter which must be connected to the control setXXX() slot. This means that for every single control attribute you want to live translate you will need a separate intermediary slot defined somewhere, a related signal for that slot with a QString argument, and two QObject::connect() calls. For every attribute we want to live translate. Obviously this gets very ugly, very fast.

I prefer to use C++ with little or no QML to lay out my app pages so I was determined to find a solution which was as easy to use as Retranslate in QML (or nearly so) and after some trial and error I came up with a solution I’m very happy with, which I called LiveTranslator. The core of this technique is a new C++ class called LiveTranslator. The usage syntax is a little more complicated than using QML Retranslate, but like Retranslate you only need to add one line of code for each attribute you want live translation on. Here is the header for LiveTranslator:

LiveTranslator encapsulates all the ugly stuff, including remembering the translation key, the intermediary slot/signal, and all signal/slot connections necessary for live translation. Using it is as simple as creating an instance of LiveTranslator, passing the constructor the translation key for the attribute (and the context, but more on that later), the target UI control, and the slot on that component that will accept the updated translation. Note that tr() only works with static key strings…

Note that there is no need to save a reference to the new LiveTranslator instance since the constructor sets the “target” control as the parent. When the control is destroyed by your app the LiveTranslator will go with it. Also note that Momentics doesn’t know anything about LiveTranslator so you won’t be warned in the editor if the slot you provide is not valid. There is a Q_ASSERT in LiveTranslator though so you will know if the connection failed when testing your app in Debug mode.

The first parameter for the LiveTranslator constructor is the “context” where the translation key is located. When you use the tr() macro (or QML qsTr() function) the code parser makes note of where it found the key and stores it in the translation file along with the key. This way you could use the same translation key on different pages, and if the context is different you could have them translated differently. Again, the Index parser doesn’t know anything about the LiveTranslator class though so you have to tell it the context explicitly. For C++ the context is always the name of the class containing the code you are translating. Also, in case it isn’t obvious, the “key” parameter must be the same value as the one used with tr() on the line before it.

There is one thing you must do before using LiveTranslator in your C++ code and that is to give it a LocaleHandler to work with. Rather than force you to pass a LocaleHandler to every instance of LiveTranslator, you tell LiveTranslator which one to use just once with a static function call. If you created your app from one of the Momentics templates then you already have a handler you can use:

If all you care about live translating are normal UI components, then you have all you need now to easily implement live translation in your C++ code. If, however, you also want to have LiveTranslator work with certain system controls, such as SystemUiButton or SystemDialog you have a little more work ahead of you. The problem is that on these classes the attributes we would want to live translate are set with functions, not slots. This means that there is no way to tell LiveTranslator how to update the desired strings since it only works with Qt slots. The solution is quite simple though, all we need is to define a “helper” class for each system component type which can provide access to the setting function via slots. Here is a helper class for SystemUiButton…

Now for the bad news. See those few lines at the end of the function after the “magic ingredient” comment? Without them live translation of SystemDialog won’t work. Unlike regular UI components, SystemDialog and its brethren don’t automatically repaint themselves or their children when you change one of their attributes. Instead you make all the changes you want and then call or trigger the update() slot. The bad news? That function wasn’t added until the 10.2 API. This means that full live translation of system dialogs is not possible below that API level. I say “full” live translation because even with 10.0 and 10.1 if you leave SystemUiButton labels at their defaults or set them to one of the values that Cascades natively knows how to translate then those labels will be live translated with no additional effort by you. For instance, if you set the SystemDialog confirm button to read “Ok” or “Confirm” then Cascades will automatically add live translation of those words into any language you change your device to and you don’t even need to use the tr() macro when setting them. By carefully choosing your dialog title and body you might be able to get most of the way to live translation even with the lower API levels. Unfortunately, I don’t know of a list of button labels that Cascades can live translate natively so you might need a bit of trial and error. If there is any good news in this it’s that unlike regular screen elements, dialogs are transient entities so the lack of live translation is only evident for a moment. The next time your user opens a dialog, even the same one, it will be correctly translated into the new language.

I have provided the source files for LiveTranslator and some helper classes so all you need to do to get live translation working in your BlackBerry 10 Native C++ code is grab LiveTranslator from github and add it to your project (and any helpers you need too), add a call to LiveTranslator::setLocaleHandler() at the beginning of your main app class constructor and then call new LiveTranslator(…) with the appropriate parameters for each control attribute you want to be live translated. I leave it to the reader to create any additional helper classes they might need. I also created an example app that you can download and run without coding anything yourself. Note that this demo app includes code that live translates a SystemDialog so you must compile it with API 10.2 or better.

The Retranslate class makes it easy to perform live translations from QML, but Cascades does not provide a similar tool for C++ code. A few lightweight classes and extra lines of code bring similar functionality to C++, and best of all you don’t have to rewrite your app to take advantage of it. Just add one line of code for each UI component attribute you want to translate and the LiveTranslate class will take care of the rest.

In my previous post, “How to Launch Your App in the International Market,” I showed you a few best practices for localizing your app and launching it in international markets. In this post, I’ll go over how to localize and translate UI strings in your app.

Step 1: Developing Your App

When you create a new BlackBerry project using Cascades in the Momentics IDE, it’s already configured to support multiple languages. As seen in the image below, the translations folder that contains .qm and .ts files is created, and the path of the .qm file is added to the project’s bar-descriptionor.xml file under the Assets tab. A .ts file is an XML file that maps and stores all UI strings in your app for translations and a .qm file is a compiled binary file for translation resources. Once the UI designs are finalized, the .ts files can be sent to professional translators to be localized/translated for your target markets.

If you’re like me, the next thing you may be wondering is how to update the UI strings for different locales. Typically, you need to load a translator to update UI strings and formats according to the new locale. The good news is that Cascades also takes care of this process by loading the translator in the ApplicationUI constructor on start-up, instantiating QTranslator and LocalHandler and calling onSystemLanguageChanged() method. Your app will load the correct translation resources according to the locale settings and update when the locale-related system setting is changed at runtime. This means users don’t need to restart your app to see the localized UI strings and formats according to the new locale.

See my previous post on how a translator gets loaded into your project.

Step 2: Generate Translation Resources for Target Markets

So far, there is nothing extra you are required to do for your app to support multiple languages and regions, as Cascades provides you with a good wireframe to localize your app. The real fun of developing the international savvy app begins here.

Follow the Best Localization Coding Practices

As you design and implement UI elements, identify all strings and messages to be translated and wrap them with the qsTr()/qsTraslate() function in QML or use translate()/tr() functions in C++ following the best localization coding practices posted previously. The strings wrapped with these functions indicate they are to be translated according to locale and are extracted to .ts file once the project is compiled. Needless to say, the strings that are not wrapped with these functions won’t be translated.

Once you have somewhat finalized User Interfaces and UI strings for a default language, the next step is to generate translation resources (.qm and .ts files) for each target language. It is quite simple to add target languages on the Localization tab under the bar-descriptor.xml and build the project. When the build process is completed, you will see that .qm and .ts files are created in the translations folder for each target language you added for localization (see the screen below from the“hellocascades” sample app). Each .ts file contains all UI strings to be translated in xml file format including the target language and location of the filename containing the strings. You can also generate the .ts file by running a command line tool lupdate.

Now you are all set for UI translations! You can manually insert the translated strings by editing the line “<translation type=”unfinished”></translation>” to “<translation>Hola Mundo</translation>”. Assuming most developers are not professional translators, you can get professional translation agencies to translate the UI strings; most professional translators understand the .ts file. You can just send them the automatically generated .ts files and get the translated .ts files back. Qt supports Qt Linguist tool for string translations for .ts files and some translation agencies might use Qt Linguist tool among other translation tools. During the translation and testing phase, it’s always good to keep the communication open with translators, providing them with as much information as possible to avoid ambiguity.

When translation process is complete, you can put the translated .ts files back to the project in the translations folder and build the project to regenerate translation resources, including .qm files for the app. The localized .ts file looks like below:

You can check out our “Hello Cascades” sample app to learn more about targeting multiple languages in BlackBerry 10.

Step 3: Test the Localization and Launch Your App!

Your app is almost ready for the world! Next step is testing your app against all target languages to make sure the localized UI strings are displayed correctly without truncation. Once testing is done, your hard work is paid off; your awesome app is now internationally awesome!

Any questions about launching your app internationally? Let us know in the comments below.

So you launched your app in BlackBerry World for North American users and got awesome reviews. In fact, so many people in Brazil heard that your app is great that they want to download it as soon as possible. You’d love to utilize this momentum and launch the app quickly in the Brazilian market for even more success. Simple! Just translate some UI text and messages into Portuguese and launch the app in Brazil! Google translator works pretty good, right?

Well, you would be disappointed if I told you it won’t be as simple as you would think to localize the app smoothly unless you planned it from the beginning. Besides correct translation, there are various localization-specific issues that you should consider. The good news is it’s not completely impossible. BlackBerry 10 platform provides you all you need for your app to launch in the different regions in the world. With early design considerations and well executed development plans, you can quickly localize your app for the target markets and maximize the potential revenue.

Here is how you do it!

Think Internalization starting from day 1

Designing UI Elements

When designing your app, keep in mind that it will be localized into different languages. Design user interface elements with the space to accommodate localized messages and text input. When text is translated from English to other languages, it usually gets longer. Consider wrapping text in multiple lines, applying auto scroll or displaying ellipsis in localized strings, and define methods to resize horizontally and vertically for buttons, lists and labels. Your text strings should not overlap borders or the screen edge in any of your target languages. The table below shows the average growth in length when English text is translated. A 100% growth indicates that your 4 character English word is very likely to be 8 characters long in some other language.

For graphic images, avoid using cultural specific images or symbols. What is a well understood and accepted image in one culture may be inappropriate or offensive in another. Also, avoid using text in graphics. Text inside graphics is hard to localize and time consuming because you may have to redraw or recreate the image in each localized language.

It would be ideal if you design and use one user interface layout for all supported languages. Sound too good to be true? It can be achieved by identifying the target languages early and getting the translated text/strings ready during the UI design phase to test the app. That can also lead to improved communication with translators during development.

Identify Target Languages and Locales in Advance

As mentioned, the earlier you identify the target language(s) the better for designing UI and implementing your app. Decide the target regions first, then the language and locale so it becomes clearer for localization. As soon as UI strings and design are stable, send all user visible strings for translation to a professional translation vendor and provide as much information as possible with comments and disambiguation arguments. It’s always good practice to version every iteration of translation files and to keep one translation file for each target language. In my next blog article, I will guide you how to generate, translate and package the translation resources such as .ts and .qm files in detail.

Localization also involves adapting to the region specific locale formats like numbers, currency, dates, time and measurements. You can use internationalization APIs to support the many region locales available on the device, and as long as the APIs are implemented correctly, you don’t have to do anything specific to support any particular region locale. What is this mean? See the region formatting locale section below for more.

Follow the Best Localization Practices when Coding

Qt uses translation contexts by default. The standard translation methods are tr() for C++ based strings, and qsTr() for QML based strings. These methods use the default translation context. The default context is determined by the C++ class or the QML file that the string appears in.

At runtime, translations are looked-up based on a key. This key is a combination of the context and the actual source string. If you refactor, and for example, move a string from one class to another, then the context changes and the linkage to the existing translations is broken. This makes translations more fragile. For this reason, we recommend using custom contexts. Strings with custom contexts are refactor-proof.

For custom contexts, you need to use the QCoreApplication::translate (C++) and qsTranslate (QML) methods. Both of these methods accept a custom context as the first parameter and the actual source string as the second parameter. In this blog post, I will demonstrate all the C++/QML translation functions.

Disambiguating strings in the same context: Use comments and disambiguation arguments to provide information to translators. You can also create separate strings for use in different contexts. Suppose you have the same string in one context, but it means two different things. You can differentiate/disambiguate the two meanings by using the optional third parameter to the QCoreApplication::translate() (C++) and qsTransate() (QML) methods:

Note that this rule applies to punctuation too. Always include punctuation such as colons, question marks, etc. in the source string. Some languages require extra spaces between text and punctuation marks, and some languages require completely different punctuation marks.

Plural forms: Rules for plural forms are different in some languages. Generally for plural strings, pass an additional integer argument to the translation functions. For example:

Note that in above example, the number is not formatted according to current locale in tr() function. For example, it won’t be rendered using Arabic numerals in Arabic locale. In order to get the correct number formatting based on the specific locale, we can use:

You can also listen for the changed() signal in C++ to be notified whenever the user changes the specified QNX BB10 locale. The locale() function returns a QLocale instance presenting the currently selected locale. Qt 4.8 provides set of internalization APIs to perform correct localization. QLocale class provides most of the localization APIs, while BlackBerry 10 OS supplements and extends the Qt’s APIs with libraries of its own like bbsystem, bbutilityi18n and QtCollator to bridge the gap from Qt 4.8. More details about BlackBerry 10 OS internationalization support can be found on our developer’s site.

Translation methods: Use QT_TR_NOOP or QT_TRANSLATE_NOOP if you need to mark a string for translation, but do the runtime translation later.

Language fallback: Note that language fallback takes place. For example, if the language is set to ‘pt_BR’, then Qt will look for the ‘pt_BR’ resource. If it can’t find the ‘pt_BR’, then Qt looks for the ‘pt’ resource. If the ‘pt’ can’t be found, then Qt falls back to the untranslated strings.

Font fallback: Cascades is integrated with a text layout engine that handles complex text languages like Arabic, Thai, and Hindi, and BlackBerry OS includes fonts for most scripts. Cascades supports font fallback automatically, so if user specifies some font X to use and then requests to draw glyph Y (which is not present in font X), Cascades will automatically fallback to a font family that contains the glyph Y and is the nearest match to the user requested style and use that to draw Y.

Use Unicode encoding: Unicode is a character encoding standard that provides a unique number for every character and symbol in various languages. It is the basis for translatable software and international content creation. UTF-8 is the default encoding of BlackBerry 10 devices and developers should use UTF-8 for all source code, including translatable files, and then use QString::fromUtf8() for string literals. For more information about encodings, see the Qt documentation.

Handle Dynamic Locale Change: Your app should update the UI strings dynamically when the user changes the UI language and/or locale device changes its locale. Cascades supports dynamic translation so that when the UI language and/or the region locale is changed, the visible strings and formats get updated according to the changed locale. It could be as simple as the sample code below to translate the strings dynamically.

Install Translator: In order for source texts to get translated, the application needs to parse in translation resources. This is typically done in the constructor of the application by loading a resource file into a translator, and then installing the translation. Then by calling “onSystemLanguage()”, the app updates UI strings/formats according to the new locale.

Test! Test! Test!

Test your app early and often to make sure the localized app is acceptable. Test country and language dependencies for the app. App data and user interface for conformity should also be tested to the locale’s standards for date and time, numeric values, currency, list separators and measurements. It is always good to consult with local users and/or region experts to ensure cultural acceptance of images.

Last but not least, stay tuned for our part 2 on this topic. I will guide you through how to generate, translate and package the translation resource within QNX Momentics IDE to get you ready to launch your app in different markets. That’s it for now. I hope you enjoyed reading this blog article.

Let’s start making international savvy apps!

]]>http://devblog.blackberry.com/2014/02/launch-your-app-in-international-market/feed/0Localization_1_featureechotownLocalization_1_1Localization_1_2BlackBerry App Internationalization: Language, currency and address supporthttp://devblog.blackberry.com/2012/05/app-internationalization/
http://devblog.blackberry.com/2012/05/app-internationalization/#respondThu, 31 May 2012 14:49:41 +0000http://devblog.blackberry.com/?p=9641]]>Did you know that you can internationalize your BlackBerry® application using the JSR 238? More specifically, you can do the following to your BlackBerry application so that your app is ready for the international market:

Multiple language support

Localization of currency

Localization of addresses

Detecting which country the user is located in (in the event that you have certain content that you only have license to serve in certain geographies)

In this blog post, we will look at the multiple language support in detail – the rest of the above topics will be covered in upcoming blog posts here on the Inside BlackBerry Developer’s Blog.

All commercial applications these days should be localized, and BlackBerry uses net.rim.device.api.i18n package to enable seamless localization.

If your application is localized, it will be displayed in the local language out of the box. So if the default locale settings on one device are set to English and French on the other, the application will be displayed in the correct language on both devices without any need for interaction from the user.

Setting up a New BlackBerry Project

This blog post assumes that you should already know how to set up and configure a new BlackBerry project in Eclipse™. If you need a reminder, refer to this link.

If you read the code carefully, you will notice that our LocalScreen class implements LocalDemoResource. Also new is the ResourceBundle variable _res which is used when creating our fields. To be able to use and explain them, we will first create our resource files.

Creating resource files

To be able to localize your application, you need to create .rrc and .rrh files. It is quite easy to create these files in Eclipse. Click on File->New->BlackBerry Resource File and browse to the location of your package. You will need to name your header file here — let’s call this file LocalDemo.rrh (make sure you include the extension). Pressing Finish on this screen will now allow you to implement LocalDemoResource interface.

If you called your .rrh file “exampleResource.rrh”, then the interface name would be exampleResource. Now we need to create resource files for each language:

The parts of the name _fr and _es are default endings for those languages and cannot be changed.
If you did everything correctly, you should have 4 resource files just under your Local.java file. Now we need to edit these files. Double click on the LocalDemo.rrh file — this is the one which contains all the keys. Select the ‘Add Key’ Button and add the following fields:

CLOSE, ENGLISH, FIELD_TITLE, FRENCH, GOODBYE, MESSAGE, SPANISH.

You do not need to enter the values on this page. When you double-click on the LocalDemo.rcc file, it will open the screen where you can fill in the values. You can access the values for French and Spanish locales by clicking on the tab on the bottom of the window (marked fr or es), or by double-clicking on the file name.

As you can see, special characters used in these languages such as ‘ó’ in word “adios” or ‘ñ’ in “Español” were used. The system will use those characters and display them when needed. You can use any Unicode characters here, which means you can support languages such as Chinese or Arabic.