Search this site
How to localize a program made with REALbasic / Real Studio
Have you written a program in Real Studio that is used by others? Are you now thinking about adding translations into other languages to your application?
Then read on, you might be surprised what's in store for you...
REALbasic provides a nice way to handle the support for multiple languages: Dynamic Constants
Instead of writing your text directly in your source code, you create Constants and check their "Dynamic" option.
Similarly, text in windows, such as the caption of a Label or Button, is turned into dynamic constants by entering the constant's name, prefixed by "#", in place of their text, as seen here:
Now you can use the button in a Constant declaration to add a translation for another language:
However, adding the translated texts by hand for each dynamic constant would be quite tedious if you have 100s of dynamic constants waiting for translation. Luckily, Real Software has provided a free tool to help with this: Lingua
The Lingua application is part of the Extras that come with a complete Real Studio installation, and is also available separately as a download at Real's web site.
Lingua lists all dynamic constants in one window. You can see the original language (e.g. English) and enter the translation for another, previously chosen, language.
To use Lingua, you first need to export the dynamic constants from your project to a ".rbl" file: In the IDE, with your project open, choose '''Export Localizable Values..."' from the File menu. The following dialog will appear where you can choose the language you want to translate your app into:
Once saved, you can open the .rbl file in Lingua.
Here's how it looks in Lingua then:
Simply click on the gray items in the left list (the black ones are already translated), fill in their translation text in the bottom right and save it back to the .rbl file once all items are translated.
As a last step, back in the IDE, choose "Import" from the File menu and load the finished .rbl file. When you now go back looking at the dynamic constants, you'll find that they all have a new translation entry.
Now you can build your localized app.
For Mac OS X, do you not need to worry about choosing a language in the Build Settings - just leave it at "Default". The built app will contain all translations automatically (You'll find them if you view the app's package contents, then go into Contents/Resources - there will be one or more folders ending in ".lproj", one for each language).
For Windows and Linux I am not sure. Maybe you'll need to build the app for each separate language, maybe not. That's not part of this tutorial :)
What if you have written a huge program, with lots of texts in it that need translation, but you have not converted them into dynamic constants yet? Are you facing a tedious process to turn them all manually in dynamics?
Well. Up to now, yes, probably. From now on, consider Arbed.
Arbed, which is a tool to work with project files, can be seen as an extension to the IDE's editor. It can search, edit and convert project files in ways the beginning Real Studio user wouldn't probably need. In that way, Arbed is more of an advanced tool. But see for yourself:
First off, make sure your project is not opened in the Real Studio IDE. Launch Arbed and drag the project file onto Arbed's "Project Editor" panel. This will open the project browser.
Note: Arbed can only open .rbp and .xml files. If your project is saved in the version control format, you need to save it as a .rbp file first.
Arbed has one simple command under its Search menu: Localizable Strings
Choosing this command will show something like the following:
Here you see two windows:
Now, all you have to do is to select all those items that you want turned into dynamic constants and click on Make Dynamic.... You'll then get to choose a module - that's where the dynamics constants will be created:
If you have no module for your translations yet, close the project window in Arbed (groupings and exclusions you made so far will be preserved), open it in the IDE, add a new module there, name it ("Tr" is a good choice) and save it. Then re-open in Arbed and go back to this step.
If all goes well, the selected entries will disappear from the list as they've now become dynamic constants, like here:
Save the project and you can re-open the project in the IDE.
Since you might want to use this operation more than once on a project, you can also mark all those entries that should never be considered for localization (because they're internal strings not shown to the user), by selecting them and clicking on "Exclude", or simply by pressing the "e" key. To show the once-filtered items, check the "Show Excluded" box - the filtered items will appear in italics.
The filtering choices will be remembered in an auxiliary file next to the project file, with the extension ".arbed". Should you move or rename the project file, don't forget to include this extra file to keep the filters intact with Arbed.
Every single (non-italic) item in the list will be turned into their own constant. However, if you have lots of buttons labeled "Cancel", you might want them all to use a single dynamic constant. To accomplish this, use the "Group" command:
Select any item that has multiple text occurances in the list. If you do that, two things happen:
Example before grouping:
Example after grouping:
As you can see, once a group has been bound, the Group button turns into "Un-Group", allowing you to unbind the group again.
The group bindings will be remembered in the .arbed file.
The leftmost column in the list shows the name the constant will get when being created in the "Make Dynamic..." process.
All list items are initially preset with a name made from their text.
You can change these names by clicking into the list cell:
The explicitly set names will be remembered in the .arbed file.
When the constants get created during "Make Dynamic...", the name shown in the Name column will be used. However, if that name is empty or not unique, then a number will be appended to the name until it's unique.
Maybe you've experienced this yourself before when using Lingua:
If you have a string that ends with a space character, such as in "value: ", then it's easy to miss this detail in Lingua, and so the translation may end up with a missing blank there.
Arbed takes care of this for you: It separate white space (spaces, tabs) that appear at the start or end of a string in code, and only turns the "trimmed" part of the string into a dynamic constant. An example:
with ConstantName = "value:"
I needed a few improvements that Lingua doesn't offer, and so I wrote a clone of it and made it open source.
Special features include:
Here's OpenLingua's web site.
If you like to make improvements and share them, please fork the project into your own github account, make your modifications there and then send me a request to merge your changes into my main version. Or just send me your modified project and I'll be using Arbed's diff+merge feature to adopt your changes.
One of the bigger problems with translations is usually that their text is longer, especially if translating an English program into German or French. Therefore, you need to double check if the translated text actually fits into the space you've reserved for it in your user interface elements. As one usually tends to size the controls just large enough to snugly fit the text, this will be a hassle for the translation process.
Here's an example of a window showing english texts:
The width of the "Find" button appears wider than necessary - that's because it reserves the space for the alternative text ("Find All").
And the same with german texts. Note how controls are resized and even moved along:
Ideally, you'd have a way to auto-resize your controls to the needs of the text that's being shown. Other programming environments had or have such a mechanism, e.g. Java and Qt. With REALbasic, I know of two options:
You can download my version here.
I use my own solution in Find Any File, so all you get from me is just that much as I needed myself. Feel free to expand it. If you do, I suggest you start a repository at github so that others can contribute to it, too. Let me know and I'll link to it.
As explained above, the translation is usually done by using the Lingua app. But in order to include the translations back into the program, the .rbl file has to be re-imported using the IDE, then a new app built from it. An external translator may not be able to do that himself.
In case of OS X at least, there's an alternative: As the translation files end up as ".strings" files in the app's bundle, the translator can edit those directly, thereby immediately seeing the results.
The problem with this is, however, that the translation will end up in a .strings file, not in Lingua. What's missing here is a tool to import a .strings file back into either Lingua or the project file. Again, OpenLingua to the rescue! As of April 5, 2011, OpenLingua can import .strings files, making it possible for us all to accept translations made by fellow users of your Mac apps, even if they do not know about Lingua or Real Studio.
Consider you having code like this:
Now imagine that the translator needs to change the order of the words for some reason, maybe the language grammar requires it, so that the text would end up more like this:
Note that this swapped the values of x and y.
But if you write your code like above, then the translator can not influence the swapping of the values as necessary.
The general solution to this is: Avoid using "+" to concatenate strings and dynamic values. Instead, form one string with placeholders for the values. That way, the placeholders can be re-arranged by the translator.
Here, the translator will see a single string for translation: "^1 items out of ^2 items were replaced."
So, keep this rule in mind: Avoid the plus sign in the strings you want to have localizable.
There's is an illogical behavior in the current IDE (2011r1) when it comes to building apps with dynamic constants. The effect of it is that, using the same project and the same IDE, you may get inconsistent results depending on your currently chosen system language on OS X. Which means: The environment that you're using influences the results of your builds - which can easily cause problems when you, for instance, build your app on a different Mac and you do not make sure that it uses the same system language.
This problem only occurs if you are using Default values for your localizable dynamic constants. Those default values will be assigned to your current system language when you build an OS X application.
And the solution is quite easy as well: Make sure to open the Build Settings of your localized project and change the Language from Default to the language which you used for your default values in the localized Constants.