iModernize - The Profound Logic Software Blog

The Language Barrier

Posted by Scott Klement on Aug 9, 2013 11:39:54 AM

I was given the interesting assignment of changing Profound UI so that any runtime messages would be available in any language chosen by the customer. I can definitely see why. Prior to this project, most of the messages that the product provided were in English, which is clearly not suitable for non-English speakers.

The Challenges

The tricky part was figuring out how best to do it. Here is a list of challenges:

  • We can't possibly provide every single language on the planet, so a customer should be able to provide his own language files, if desired.
  • A customer should be able to rephrase/replace any of our messages with his own.
  • We have many existing configurable messages that a customer can override with his own text. We need to preserve backward compatibility.
  • This should all run on any web browser, and run fast.

Note that I'm really only concerned about runtime messages at this point. Developers should understand English sufficiently well to design and code their programs with English labels and help, but the end-users who run our applications are a different story. They should be able to see all of the text and messages in their own language.

The Solution

After conferring with colleagues, we decided on a solution that involves creating a "language dictionary". Right now, we have two dictionaries, one for runtime messages (such as error messages or warnings) and one for runtime text (such as screen/widget labels.) We can add more dictionaries in the future, if we ever need them. Within each dictionary is a set of languages. The customer can add additional languages to the dictionary, or use the ones we provided. Within each language is a set of "message keys" that identify a particular message that can be placed on the screen at the appropriate time. The message keys are simple strings that descriptively identify the message.

Since the Profound UI framework is written in JavaScript and runs in the web browser, I carefully planned it so that our messages are loaded into memory first. Then, customer's messages are loaded. When the framework needs to display a message, it calls a function pui.getLanguageText() that gets the proper message in the desired language. This function also checks to see if the customer is using one of the original styles of message strings, and if so, uses that instead of the one from the language dictionary to preserve backward compatibility.

This was implemented as a set of JavaScript objects, coded like this:

<strong>pui[dictionary-name][language-code][message-key] = "The message string."</strong>

Where:

  • dictionary-name = The name of the dictionary. Right now, we have runtimeMsg and runtimeText as dictionaries in Profound UI. In the future, we may decide to use more.
  • language-code = I decided to use the ISO language codes. Currently Profound UI provides the following languages pre-defined, but you can add any that you want:
    • en_US = English/USA
    • en_UK = English/UK
    • de_DE = German/Germany
    • es_ES = Spanish/Spain
    • es_MX = Spanish/Mexico
    • pt_PT = Portuguese/Portugal
    • pt_BR = Portuguese/Brazil
    • fr_FR = French/France
    • it_IT = Italian/Italy
  • message-key = identifies the specific message to display (within the language and dictionary)

Specifying a Language

To specify a language, you'll want to create a file named language.js in the /www/profoundui/htdocs/profoundui/userdata/custom directory of the IFS. This is where you'll type your language settings.

How you get the settings to load into your Profound UI session depends on which environment you're running your rich displays from:

  • From a Profound UI session, any files in the userdata/custom directory given above will automatically be loaded into the browser. You don't need to do anything else.
  • From a Genie session, edit the start.html file in your Genie skin. Add <script type="text/javascript" src="/profoundui/userdata/custom/js/language.js"></script>. It should be placed immediately after any other <script> tags in the file.
  • From a PhoneGap project, edit the index.html file and add <script type="text/javascript" src="http://yourserver:8080/profoundui/userdata/custom/js/language.js"> after any other script tags in the index.html file.

These statements will cause the Profound UI framework to load your language.js file into the browser so that it can read the settings from it. To use one of our predefined languages, you should put the following in the language.js file:

<strong>pui["language"] = "en_US";</strong>

Replace "en_US" with any of the language codes listed above. Once you save your settings and re-load Profound UI, you should get all of the messages and text in the language you've chosen.

It does so by reading the dictionary like this:

message = pui["runtimeMsg"][<strong>the pui-language setting, above</strong>]["message key"];

If you do not set a pui["language"] value in this manner, Profound UI will default to "en_US" (English for USA).

Modifying the Strings for a Language

If you wish to change the way a message or text label is phrased for a given language, you can do that simply by adding an additional setting to the language.js file. First, make sure you've created a language.js file (as described in the "specifying a language" section, above.) Then specify the new string using the dictionary/language-code/message-key as described above.

For example, when a subfile grid has it's "export csv" option enabled, a text label normally appears at the bottom of the grid that says "Export to Excel". Perhaps you'd like to say that differently, if so, you could define it like this:

<strong><code>pui[</code><code>"runtimeText"</code><code>][</code><code>"en_US"</code><code>][</code><code>"csv export text"</code><code>] = </code><code>"Open in Excel"</code></strong><code>;</code>
Now it'll say "Open in Excel" instead of "Export to Excel" if you are using the English/USA language. If you'd like to change the text to a different language, simply specify a different language code instead of "en_US".
There's a list of all of the message keys that you can override in the "Defining a New Language" section under "Language Support" in the Profound UI manual.

Adding Your Own Language Definition

To add a new language aside from those that Profound UI provides, you can simply create the proper JavaScript objects in your language.js file. You can create any language you wish by specifying a language with a different string.

For fun, let's say that I wanted my instance of Profound UI to sound like the cartoon character, Elmer Fudd. To do that, I could create a new language dictionary named "fudd", and set my pui["language"] setting to the fudd language. The following JavaScript statements will set my language, and create the needed JavasScript objects:

<strong><code>pui["language"] = "fudd";
pui["runtimeMsg"]["fudd"] = {};
pui["runtimeText"]["fudd"] = {};
</code></strong>
Now that I have the proper JavaScript objects, I will need to define all of the messages in the new Elmer Fudd language. To do that, I can add the following lines of code (they should go after the preceding ones) to my language.js file:
<strong><code>pui["runtimeMsg"]["fudd"]["closeMessage"] = "Dis wiww end youw session, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["no connection message"] = "Unabwe to weach sewvew. Check youw connection and twy again, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["upload file limit"] = "Wimit of &amp;1 fiwe(s) exceeded.";
pui["runtimeMsg"]["fudd"]["upload size limit"] = "Wimit of &amp;1MB pew fiwe exceeded";
pui["runtimeMsg"]["fudd"]["upload no files"] = "No fiwes sewected.";
pui["runtimeMsg"]["fudd"]["upload duplicate file"] = "Dupwicate fiwes sewected.";
pui["runtimeMsg"]["fudd"]["upload file exists"] = "One ow mowe fiwes awweady exist on the fiwe system.";
pui["runtimeMsg"]["fudd"]["upload prevented"] = "Opewation pwevented by exit pwogwam.";
pui["runtimeMsg"]["fudd"]["upload input limit"] = "Totaw input size wimit exceeded.";
pui["runtimeMsg"]["fudd"]["upload no session"] = "Not connected to a vawid session, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["upload timeout"] = "Twansaction timed out.";
pui["runtimeMsg"]["fudd"]["upload invalid response"] = "De sewvew wesponse is missing ow invawid.";
pui["runtimeMsg"]["fudd"]["close browser text"] = "To compwete the wog off pwocess, pwease cwose youw bwowsew window.";
pui["runtimeMsg"]["fudd"]["session ended text"] = "Youw session has ended.";
pui["runtimeMsg"]["fudd"]["outside ucs2"] = "Chawactews awe outside of UCS-2 wange.";
pui["runtimeMsg"]["fudd"]["invalid number"] = "&amp;1 is not a vawid numbew.";
pui["runtimeMsg"]["fudd"]["invalid length"] = "&amp;1 has an incowwect data wengf ow decimaw position, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["invalid decimal"] = "&amp;1 has too many decimaw pwaces. Oh, dat scwewy wabbit! (max: &amp;2)";
pui["runtimeMsg"]["fudd"]["invalid choice"] = "\"&amp;1\" is invawid. Vawid choices awe: \"&amp;2\" ow \"&amp;3\".";
pui["runtimeMsg"]["fudd"]["invalid date"] = "\"&amp;1\" is not a vawid date. Exampwe fowmat: &amp;2";
pui["runtimeMsg"]["fudd"]["invalid time"] = "\"&amp;1\" is not a vawid time. Exampwe fowmat: &amp;2";
pui["runtimeMsg"]["fudd"]["invalid time stamp"] = "\"&amp;1\" is not a vawid time stamp. Exampwe fowmat: &amp;2";
pui["runtimeMsg"]["fudd"]["invalid percent"] = "&amp;1 is not a vawid decimaw.";
pui["runtimeMsg"]["fudd"]["invalid digits"] = "\"&amp;1\" contains too many digits. Oh, dat scwewy wabbit! Max: &amp;2";
pui["runtimeMsg"]["fudd"]["exceeds whole"] = "\"&amp;1\" exceeds the maximum numbew of digits fow the whowe numbew powtion (&amp;2 digits).";
pui["runtimeMsg"]["fudd"]["exceeds decimal"] = "\"&amp;1\" exceeds the maximum numbew of digits fow the decimaw powtion (&amp;2 digits).";
pui["runtimeMsg"]["fudd"]["zip too long"] = "Zip code is too wong. (Maximum: &amp;1 digits)";
pui["runtimeMsg"]["fudd"]["phone too long"] = "Phone numbew is too wong. (Maximum: &amp;1 digits)";
pui["runtimeMsg"]["fudd"]["ssno too long"] = "Sociaw secuwity numbew is too wong. (Maximum: &amp;1 digits)";
pui["runtimeMsg"]["fudd"]["invalid custom val"] = "Invawid custom vawidation function, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["error custom val"] = "Ewwow in custom vawidation function, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["ME"] = "Mandatowy entwy fiewd. You must entew data.";
pui["runtimeMsg"]["fudd"]["MF"] = "Mandatowy fiww fiewd. You must fiww the input box compwetewy.";
pui["runtimeMsg"]["fudd"]["required"] = "De vawue cannot be bwank. Dis fiewd is weqwiwed.";
pui["runtimeMsg"]["fudd"]["file required"] = "You must sewect at weast one fiwe.";
pui["runtimeMsg"]["fudd"]["signature overflow"] = "De signatuwe dwawing size exceeds the maximum numbew of bytes avaiwabwe fow stowing the signatuwe. Pwease cweaw the signatuwe pad and twy again, uh-hah-hah-hah.";
pui["runtimeMsg"]["fudd"]["validValues"] = "Vawue entewed is not vawid. Vawid vawues awe:";
pui["runtimeText"]["fudd"]["upload select text"] = "Sewect Fiwes";
pui["runtimeText"]["fudd"]["upload clear text"] = "Cweaw";
pui["runtimeText"]["fudd"]["upload remove text"] = "Wemove";
pui["runtimeText"]["fudd"]["upload upload text"] = "Upwoad";
pui["runtimeText"]["fudd"]["csv export text"] = "Expowt to Excew";
pui["runtimeText"]["fudd"]["filter text"] = "Fiwtew";
pui["runtimeText"]["fudd"]["remove filters text"] = "Wemove Aww Fiwtews";
pui["runtimeText"]["fudd"]["next link text"] = "Next";
pui["runtimeText"]["fudd"]["previous link text"] = "Pwevious";
pui["runtimeText"]["fudd"]["sort ascending text"] = "Sowt Ascending";
pui["runtimeText"]["fudd"]["sort descending text"] = "Sowt Descending";</code></strong>

Even though "fudd" is not an internationally recognized language, and was not shipped with the system, I was able to add it simply by defining "fudd" as my pui["language"] value, and then defining the proper messages for my new "fudd" language.

This is just an example, and it's important to understand that as time goes on Profound Logic will keep adding additional message keys to the product. When that happens, the new keys will not be added to this blog entry, but they will be added to the official Profound UI Documentation for Language Support. Please visit that page to get a comprehensive list of all of the needed message keys.

Topics: Development, New Features

Subscribe to Blog Updates

....and get our "How to Get Full Business Buy-In for Your Modernization Project" ebook!

business buy-in ebook

Recent Posts