i18n Tip: Concatenating Strings at Runtime

May 9th, 2011 by Dario Solera | Filed under Amanuens, Best Practices.

One of the first thing we should take into account when internationalizing an application is how to handle complex localizable strings. This is particularly important in web applications, where text is usually interleaved with links or other markup, for example:

When you are done, click on the <b>Save All</b> button to save your changes.

The Wrong Way

It’s tempting to assume that including markup in resource files is bad, so we split the string in three pieces, like this:

When you are done, click on the
Save All
button to save your changes.

Those pieces would be assembled at runtime, adding the appropriate <b> and </b> tags.

The problem with this approach is that we are assuming that, in each language, the pieces would still make sense after assembling them (or that the translator would be able to figure out what the pieces mean at all). This is one of the most common mistakes we could do when internationalizing an application.

In the example above, however, we could simply leave the markup in the string and have the translator figure out what to do with it. If you’re using Amanuens, then you don’t have to worry because the editor assists the translator when strings contain markup.

A Better Way*

At Threeplicate we use another way to handle the same string, or a more complex one (BTW, Amanuens is still available only English, but it’s fully internationalized). Lets use this example:

<b>Note</b>: before committing changes, you should <a href="dynamic URL" title="Go to translation synchronization" class="navigation active">synchronize</a> the translation.

In this case the <b> and </b> tags are the least of our problems. As you can see, there is a link whose URL can only be determined at runtime that makes things much more difficult.

The obvious solution would be to use a placeholder to inject the correct URL at runtime. In my opinion, that is a sub-optimal solution, for a number of reasons (see below).

Instead, we can store the string in 3 pieces, but with a rationale:

<b>Note</b>: before committing changes, you should {0} the translation. // {0} = "synchronize"
synchronize // As in "you should synchronize the translation"
Go to translation synchronization

We specify in the comments (or translator instructions) that {0}** is a placeholder for “synchronize” and how “synchronize” is used. At runtime, we replace {0} with a working link (whose URL is determined according to application’s logic and whose title is pulled from resource files as-is), regardless of where the placeholder is.

This approach gives us 4 benefits over the URL-placeholder solution:

  1. we are certain that the {0} placeholder is in the right position, regardless of the current language
  2. we avoid to store too much markup in resource files (a bold tag is fine, a whole link is perhaps too much)
  3. we avoid to include any kind of logic/navigation/semantic in resource files that could easily be broken during translation
  4. the translator has context information helping her producing high-quality results.

Your turn. Tell us what you do in similar cases!

* Better and not Best because there surely are other options. It’s just that this one works quite well for us.
** I’m using {0} in this example because it’s the placeholder format used by the string.Format method in .NET – you can use any type of placeholder. Remember that Amanuens assists the translator with placeholders too, not just with HTML markup!


Leave a Reply