Critical Path Newsletter
Localization - A world of difference
Would you ship this product (below) to your customers?
Companies ship GUIs like this every day—for non-English-speaking editions. Maybe you think I’m making this up, but I’ve seen “Global” versions that are every bit as badly translated and localized as this example.
Luckily, your team can avoid common localization problems with thirty minutes of training, and by following these guidelines:
- Plan localization from the start
- Be smart about encoding
- Establish (and follow) string handling rules
- Keep cultural localization in mind
Plan localization from the start
All desktop client applications should be designed for easy localization, but the localization framework is often a low priority. Adding the framework late in the cycle results in an inflexible, buggy, and difficult to maintain localization framework.
When planning localization, decide:
- What kind of string tables to use
- How to store GUI information (positioning, size, etc.)
- How to determine the user's language/culture (OS setting, browser setting, app preference, etc.)
- Classes to use for string table access and manipulation
- The steps for adding/changing a string
- What encodings to use
- To use localizable 3rd-party software
Be smart about encoding
Can you see the difference?
|String 1||String 2|
|Hello World!||Hello World!|
For people, they look the same. To your application, there could be a world of difference.
You probably guessed the difference is the encoding. To an application, whether the string is a char*, wchar_t array, std::string, std::wstring, or CString means nothing. Something is missing. The software needs to know how strings are encoded.
When working with strings, the developer has to know:
- what encoding the string uses now.
- what encoding the function expects the string to be in.
For example, take a string encoded in ASCII using the default code page. Does the function you pass expect a Unicode UTF-8 encoded string? Find out for sure. The two minutes it takes saves an hour of hair-pulling down the road.
To help your team with this task you can:
- Ensure your team understands all strings are encoded (many developers don't realize that) and what the possible encodings are.
- Establish coding guidelines to help people reading the code understand it and identify mistakes.
Coding Guideline Example
// UTF-8 string
// You can't treat a UTF-8 string as an
aFirstName = u8FirstName;
Establish (and follow) string handling rules
Rule 1: Don’t reuse string table entries.
Take, for example:
Repress the urge to use this string to retrieve calls and also to retrieve e-mail. In another language, the verb for getting calls might be different than the verb for getting emails.
Use each string in the string table in exactly one place in the GUI.
Rule 2: Allow formatting parameter re-ordering.
Sentence structures vary between languages. When formatting a string, allow re-ordering depending on language.
In C/C++, the most common parameter ordering mistake is writing string formatting code using printf-type format specifiers. For example:
RESOURCE_ACCESS_WARNING=Warning: %s is trying to access resource number %d
Example code using RESOURCE_ACCESS_WARNING string table entry
std::wstring message =
If the localization team puts the resource number before the username, it will fail, maybe even crashing the program.
Worse, sometimes developers use concatenation when formatting messages the user sees:
DELETED_CONTACTS=The number of contacts you have deleted is
If this is translated, the localization team has to display the number of contacts at the end of the string, which might not be appropriate in another language.
Avoid these problems by using a framework with ordered formatting parameters, like Win32's FormatMessage and Boost's format library.
This string table entry is better:
Improved String Table
RESOURCE_ACCESS_WARNING=Warning: %1 is trying to access resource number %2!d!
The parameters can now be ordered in the string table. The two parameters in RESOURCE_ACCESS_WARNING could be defined as:
Below, username is the parameter at position 1 and resourceId at position 2:
std::wstring message =
If the translation requires a different order, no problem:
RESOURCE_ACCESS_WARNING=Warning: Resource number %2!d! is being accessed by %1.
Or you can omit parameters:
RESOURCE_ACCESS_WARNING=Warning: Resource number %2!d! is being accessed.
Rule 3: Don't display strings you don't control.
When a developer wants to cut corners they sometimes re-use things that shouldn't be re-used.
Let's say you’re developing a three-tier Web application with defined layers. In lower layers, it can be common to throw or return error messages when something wrong has happened. Maybe the underlying database can't connect and sends a "Cannot connect" message to the layers above. Proper error messages help in debugging applications, however, some developers display these strings as is. If these strings aren’t localized, they can frustrate your non-English-speaking user.
To handle this, display a localized string keyed to the error. For example:
// This fetches a localized string from the string table
Keep cultural localization in mind
Localization is more than using a string table and handling strings correctly. It's also about UI design. For example, did you know that the hand icon generally used for dragging objects resembles a gesture that's been obscene in Greece since the Byzantine period and that in most Arabic countries, giving the 'thumbs up' is considered rude?
Even colors have different meanings. In North America, being 'in the red' means you're losing money--but in East Asian countries, stock market gains are displayed in red, losses in green.
Avoiding every pitfall for every language/culture would take another Critical Path–or maybe two.
But planning localization from the start, using these techniques, will save time and prevent disasters like the earlier screenshot. To enforce these rules, you could appoint a localization guru, an experienced person, to encourage others to follow best practices.
With a little planning, it's not hard to get your application localization-ready. And for your global customers, it makes a world of difference.