Local Links

External Links

Contact

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...

1.  Localization with the Real Studio IDE and Lingua

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.

1.1  Example

Unlocalizable text:


Localizable text:



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:


1.2  Adding translations, inefficiently

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

1.3  Adding translations with 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 :)

2.  Turning all your texts into Dynamic Constants

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.

2.1  What Arbed can do to help localization of your existing project

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:

  1. The big window in the background is Arbed's project browser.
  2. The floating window in front lists all the texts it found relevant for localization. (It leaves out empty strings and a few other special cases such as "-" menu items, which are just separators. And it doesn't show existing dynamic constants, either.)

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.

2.2  Excluding items permanently from localization

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.

2.3  Binding items with identical text into a group

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:

  1. All related items with the same text will be shown with a grey background
  2. The Group button gets enabled.

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.

2.4  Naming the to-be-created constants

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.

2.5  Dealing with those pesky invisible blanks at the end of a string

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:

This line:

s = "value: "

becomes:

s = ConstantName+" "

with ConstantName = "value:"

3.  OpenLingua as an alternative to Real Software's Lingua

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:

  • Build for Cocoa, so that VoiceOver can be used for those with vision impairment.
  • Can hide platform specific entries that do not need translation.
  • Pressing the Tab key won't insert an unwanted TAB key into the translated text.
  • Text can be viewed unwrapped to spot line breaks better.
  • User will be warned if spaces at start or end of text do not match the original.

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.

4.  General considerations and caveats when adding localization

4.1  Translated text may not fit

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:

  1. Einhugur provides a plugin for all platforms for this purpose, called FlowLayout
  2. I have written something in pure REALbasic, inspired by Einhugur's solution. This solution has a few flaws, though: It may cause flicker on Windows (not on Mac, though), and made for a single purpose, i.e. adjust the controls at start, once. Einhugur's, OTOH can even be re-adjusted after you've modify them at runtime.

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.

4.2  How an external translator can check if the text fits

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.

4.3  General advice on parameterized strings

Consider you having code like this:

Label1.Text = Str(x)+" items out of "+Str(y)+" items were replaced."

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:

Label1.Text = "Out of "+Str(y)+", "+Str(x)+" items were replaced."

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.

Example:

Label1.Text = Replace( Replace( "^1 items out of ^2 items were replaced.", "^1", Str(x) ), "^2", Str(y) )

Here, the translator will see a single string for translation: "^1 items out of ^2 items were replaced."
And he can adjust it as needed, e.g. to: "Out of ^2, ^1 items were replaced."

So, keep this rule in mind: Avoid the plus sign in the strings you want to have localizable.

4.4  Dynamic Constants: Default versus explicit language values

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.


Page last modified on 2011-05-27, 18:41 UTC (do)
Powered by PmWiki