Image “Displays Thanks In Foreign Languages” by Stuart Miles / FreeDigitalPhotos.net
Introduction
I recently came across a great sample application on GitHub from Roger Leblanc (@RogerLeblanc). Roger is prolific in the support forums and his sample application addresses a question that arises again and again; namely:
“How can I use the QTranslator() class and QObject::tr() which are used to manage language switching on a change of locale in my headless application?”
It’s such a common requirement yet it’s one that catches many people unaware when they try and do it themselves, using the model used in the User Interface component of their application.
So, kudos to Roger for taking the time put together a headless application sample that does this properly. My task is simply to write about it .
So, What’s the Problem?
Why is this such a valuable code sample? Well, it stems from the fact that at first glance it’s an easy issue to solve. All you might imagine you have to do is follow the same pattern that you find in the UI component of your application and everything should just fall into place.
If you follow this approach you’d be led to doing the following:
- Instantiate instances of the LocaleHandler() and QTranslator() classes;
- Subscribe to LocaleHandler()’s SIGNAL(): systemLanguageChanged() in order to figure out when the handset has had its locale changed;
- When a locale change occurs, use QCoreApplication::installTranslator() to install the appropriate locale language support you’ve put together via QObject::tr() using the QTranslator()
What could be simpler? In fact your application may build without errors but when your headless application runs things don’t happen as expected. So, what’s happened? Why doesn’t this pattern, which is embedded in the standard template for a UI application component not work in the Headless component?
Well, go back and look at the main() entry point of the UI component. It’ll look something like this:
Compare this with the main() entry point of the Headless component. It’ll look something like this:
So, now you can see the key difference between the UI and the Headless components. The UI component is an instance of the ApplicationUI() class whilst the Headless component is an instance of the Service() class. This is why things don’t work as expected in the Headless component.
The bit that doesn’t work as expected is LocaleHandler(), it has dependencies on Cascades classes via ApplicationUI(). If you’re interested you can see this difference explicitly in the .pro files for each of the UI and Headless components; the UI component contains the additional flag: cascades10, on the CONFIG keyword.
So, to make locale language translation work correctly in the headless component you have to find another way to detect a locale change instead of depending on LocaleHandler().
Just as a side note: If it had occurred to you to try and resolve this issue by simply including the cascades10 flag on the CONFIG statement in the Headless component you would find that things don’t work in even more different ways. I know, I’ve tried it .
The Solution
The cleanest solution is Roger’s, which is to replace LocaleHandler() by a custom class that can receive BlackBerry Platform Services (BPS) events through its event() callback. Something like this:
The implementation of event() watches for BPS events that represent locale changes and then emit the localeUpdated() SIGNAL() identifying the new locale to which the device has switched. Something like this:
The rest of the application follows the same pattern as the UI component from this point onwards having subscribed to the localeUpdated() SIGNAL() from MyBpsHandler() rather than systemLanguageChanged() from LocaleHandler().
Lastly, there’s one small change that needs to be made to the bar-descriptor.xml file to ensure the BAR file that’s constructed correctly contains the language translations you’ve provided for the Headless component. The path: “../TranslateHLService/translations”, supplements the translations folder in the UI component project with a corresponding one for the Headless component project:
And, you also need to instruct the build process to add support for the locales, using the appropriate file names, which your Headless component uses. Add the appropriate lines to the Headless component’s .pro file something like this, for French, English, Spanish, and Italian:
Of course you have to provide the actual text of the translations yourself .
Summary
I hope that you found this useful and give appropriate kudos to Roger for his sample application.
Please feel free to contact Roger, @RogerLeblanc at GitHub, or me, @jcmrim, via Twitter.
Resources
Roger Leblanc’s “TranslateHeadless” Application on GitHub:
https://github.com/blackberry/Cascades-Community-Samples/tree/master/TranslateHeadless
Contacts
Roger Leblanc – @RogerLeblanc at GitHub.
John Murray – @jcmrim on Twitter, or @jcmurray at GitHub.