Multilingual automation testing solution

Most automation scripts are based on English UIs. When the product is translated, there are problems, because the existing automation scripts cannot work on non-English UIs. This article describes how the IBM China Lotus Notes team resolves this issue by establishing a mechanism based on IBM Pseudo Translator to make the automation scripts work in a multilingual environment. Their solution includes generating a pseudo translation build to help programmers write automation scripts for multiple languages.

Zhi Jun Wang (wzhijun@cn.ibm.com), Software Engineer, IBM

author photoZhi Jun Wang is a globalization test leader of IBM Lotus Notes. He has worked for IBM since 2010 and focuses on automation testing in translated products.



Xue Feng Kang (xfkang@cn.ibm.com), Software Engineer, IBM

author photoXue Feng Kang is a globalization project manager in the IBM China Development Lab, focusing on IBM Lotus social software globalization and translation planning and management. He has rich experiences on globalization testing and tool development.



Xiao Feng Ji (jixf@cn.ibm.com), Software Engineer, IBM

author photoXiao Feng Ji is a developer of the globalization tool, focusing on architecture and development work for the IBM Lotus Notes Domino global workbench. He previously worked on globalization testing and engineering.



26 February 2013

The nature of the problem

Most automation scripts are based on English UIs. When the product is translated, problems arise, because the existing automation scripts cannot work on non-English language UIs.

You might ask "What if I use one unique ID to locate an object in the UI?" Yes, you can if the object has a fixed unique ID across language builds. But in our experience, most of objects' ID (.id) properties are changed when we change builds in the development cycle, even when we refresh the UI during testing. Sometimes, there is not an available ID property anymore. The reason is that the automation architect didn't take executing the automation scripts in non-English-speaking environments into consideration.

Think about the regular automation testing process. We select an automation framework — IBM® Rational® Functional Tester, for example. If we want to click the New menu item shown in Figure 1, we must use the UI string (New) to recognize this object when this UI object does not have a fixed attribute to identify.

Figure 1. Example of clicking the New menu item
New menu item in the Lotus iNotes inbox view

Tools used in this solution

PII stands for program integrated information, which IBM Terminology defines as: "User-visible text that is contained within a software program and is integral to the execution of that program. This includes user interface text and messages." We can also consider it as a set of UI strings. So we can have a set of PII files for every language that the software is translated to.

In this model, if you want to reuse the automation scripts when the UI is translated into non-English languages, you must update those scripts. Otherwise, your script will fail during execution, because the original English UI string (New) has been changed to other languages. Maintaining a set of automation scripts for each language is not an adequate option, because it wastes time. The more automation scripts that you have, the more time and effort it will require.

So you ask, "How about extracting the English UI strings and the translation?" That's absolutely a nice attempt. In the following sections, we discuss getting it into implementation stage how it will affect the process when we are creating automation scripts.


Solution overview

Automation scripts usually recognize the UI object by the attributes of that object. If the object does not have other available fixed attributes, we must select the displayed UI strings as the attribute. This means that automation scripts can't locate the right object when such attributes are changed, such as when the UI strings are translated into multiple languages. So our core idea is that we set a static unique ID for each UI object, which means that every UI string has a fixed and unique ID. No matter how many languages the UI strings are translated into, the unique ID is fixed. It's essential that we keep this unique ID consistent during multiple translating cycles and daily builds.

We map the unique ID to corresponding English UI strings and save this information in a properties file named dwa_en.properties. We use the same method to generate language properties files named dwa_xx.properties.

Properties files are stored as this list shows (the first part of the file name is base name, and the other part is the short name of language identifier):

\DWAMemory_ca.properties
\DWAMemory_cs.properties
\DWAMemory_da.properties
\DWAMemory_de.properties
\DWAMemory_el.properties
\DWAMemory_en.properties
\DWAMemory_es.properties
\DWAMemory_et.properties
\DWAMemory_fi.properties
\DWAMemory_fr.properties
\DWAMemory_he.properties
\DWAMemory_hu.properties

Then we design our mapping model according to the Java resource bundle mechanism, which makes the correct properties files that can be loaded during automation script execution. From Figure 2, you can get an overall picture of our solution. We use a unique ID to identify GUI objects in automation scripts. And all language memory files are loaded into a Java bundle when the automation scripts are executed. According to the resource bundle, the unique ID will be automatically parsed into native translation string by our Java code during the automated execution of the script.

Figure 2. Design model
Multilingual automation solution framework

Detailed steps to implement this solution

The following sections explain how we implement our solution. We illustrate the entire process, step by step.

Step 1. Create pseudo translation PII and mapping files

You can pseudo translate all PII files by using a simple that I develop (I usually called it as Mark New and Change tool). The Mark New and Change tool adds one unique ID for each PII item. In pseudo translation files, every string will have a suffix as a unique identifier. We call this suffix as the translation tool identifier. We use tool to create pseudo translation PII and mapping files, based on English PII.

Figures 3 is an example of a pseudo translation file. The unique identifier (for example, ~dwa242) is added in the end of each PII item. (The the ~ symbol at the beginning indicates a unique ID.)

Figure 3. Pseudo translation PII file example
Composition of a pseudo PII item

Figure 4 illustrates the Mark New and Change tool mapping file format.

Figure 4. Mapping file example
Composition of the mapping file

Step 2. Generate the pseudo build by using pseudo translation PII files

We'll use pseudo translation PII files to generate a pseudo build. We refer to this build to develop automation scripts. We can use the unique ID to identify the object if there is no other available fixed property.

Step 3. Create a translation memory file

We can use all pseudo translation PII files to generate one English translation memory file. Save the pseudo unique ID as the key and the UI string as the value in a properties file. Listing 1 shows an example of English memory file:

Listing 1. Example of an English memory file
dwa79=Local contact list transfer succeeded
dwa80=Change or Edit Online Status/Show Instant Contact List
dwa81=Open and save your preferences, then restart the browser before 
    launching instant messaging.
dwa82=Please enter a username and password.
dwa83=Chat
dwa84=Group
dwa85=Next
dwa86=Back
dwa87=Go Offline
dwa88=Go Online

It's not necessary to save it manually. A simple tool can help for generating memory files. We can read data from the mapping file through the Pseudo Translator tool and store the ID and English string as a pair in properties files as the code fragment in Listing 2 shows.

Listing 2. Read data from a mapping file and store it
	if(RPXMapDataStructure.map.size() == 0){
		RPXMapDataStructure.store(new File(sMappingPath));
		}
	for(int k =0 ; k < RPXMapDataStructure.getCacheData().length; k++){
	Property.add(RPXMapDataStructure.getCacheData()[k][0],
	RPXMapDataStructure.getCacheData()[k][4]);	
	}
	Property.storeWithComments(new FileOutputStream(sOutPutPath), null);

Language translation memory files can be generated by mapping file and language PII files. In mapping files, we can search for the English PII file path and the string key. According to the English PII location and given language identifier, we can deduce the corresponding language PII location. English and language PII files use the same key in a specific properties file. Normally, the language PII file path will be quite similar to English PII file path.

For example, if the English PII file path is here:
\lotus\en\message.properties

The French translation will be in this location:
\lotus\fr\message.properties

This is another kind of common file structure:

English PII: \lotus\message_en.properties
French PII: \lotus\ message_fr.properties

Figure 5 is comparison of an English memory file, on the left, and a Czech memory file, on the right. According to the Java resource bundle, we can load required language translation with the same unique ID. For example, the dwa3739 key stands for "Preview on Side" in the English file and for the translation (N\u00e1held na stram\u011b) of "Preview on Side" in the Czech memory file.

Figure 5. Compare the English memory file to language memory files
Example of a memory file, dwa3739 circled in both

We define a rule and create a module to create translation memory files. In the translation memory file, we'll use the same string key as the English translation memory. The diagram in Figure 6 illustrates the process of generating language memory files.

Figure 6. Workflow for generating language memory files
Workflow diagram

Step 4. Create a module to switch the testing language for your automation scripts

When we develop an automation test case, we try to use the fixed property, such as the ID, to identify an object as the first priority. Secondly, if no fixed property is available, we try to use a regular expression to locate an object. Lastly, if there is no fixed property available and a regular expression can't use for an object, we can use the .text property, as Listing 3 shows.

Listing 3. Example of code for identifying a GUI object by unique ID
RationalTestScript.getRootTestObject().find(
	SubitemFactory.atDescendant( ".class", "Html.INPUT.menu item",
	".text", Langfuncs.Instance().getLocalStringByID("dwa3739", "Preview on Side")	))

The getLocalStringByID("dwa3739", "Preview on Side")function shown in Listing 4 returns a string. If the current locale is English, it returns just the English string input in real automation execution. But we can store all English strings with pseudo unique ids in an English memory file, which we use for debugging and developing automation scripts in the pseudo build. If your current locale does not use English, the function will return a native translation of "Preview on Side" according to the configuration at your locale.

Listing 4. Code for loading native string from memory file

Click to see code listing

Listing 4. Code for loading native string from memory file

/**
* @sID  the unique id displayed in pseudo build* @enValue English string displayed in product, use for making program easy * to read.
* get locale strings of specified ID string
* @param sID
* @param enValue
* @return
*/
	public String getLocalStringByID(String sID, String enValue) {
	 try {
		if(gsTestLocaleLabel.equals("en_US") && !DEBUG){
		//If current locale is English, just return the English value.
			return enValue;
			}else{
			return getLocaleStringByID(sID, gsTestLocaleLabel);
		//Load translation from resource bundle file
		}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * get locale translation by unique ID using JAVA resource bundle mechanism
	 * @param sID - unique ID
	 * @param locale - this value is loaded in GVT.properties file,
	 *	 * ar_EG, ca_ES, cs_CZ , en_US, fr_FR , de_DE, el_GR , he_IL , hu_HU  ,* it_IT, ja_JP, ko_KR, pl_PL, …	 * @return String  locale string
	 */
	public String getLocaleStringByID(String sID, String locale) {
		Locale local = new Locale (locale);
		ResourceBundle resb = ResourceBundle.getBundle(
"appobjects.dwa.dwacommon.global." + gsResourceBundle, local);
		return resb.getString(sID);
	}

The gsResourceBundle parameter is a given file name prefix of a resource bundle that is stored in the \appobjects\dwa\dwacommon\global\ folder of your project. We can configure this file name in a configuration file, GVT.properties, under the current system user's home path.

Figure 7. Flowchart of searching for an object
Searching priority during test case development

Step 5. Write automation scripts using a pseudo translation build

We can pseudo translate all PII files in a special way, so that we identify a unique ID for each PII item and generate a pseudo build with the pseudo translated PII files. (See Step 1.)

Figure 8. Pseudo build example
Pseudo IBM Lotus iNotes inbox

For example, suppose that we want to click the New menu item in Figure 9, and that the unique ID is ~dwa1377. We try to get all available properties of the New~dwa1377 menu item by using the Test Object Inspector. Most of the available properties are shown in the Properties view of the Test Object Inspector, as shown in Figure 9.

Figure 9. Get available properties by using the Test Object Inspector
Test Object Inspector, Properties view

We can use .class and .id properties to identify this new menu item. In our experience, if the .id property does not include a dynamic number, the .id properties should be the same in English and native builds, in most cases. Therefore, we can identify this object as Listing 5 shows.

Listing 5. Example of finding an object by the .id property
RationalTestScript.getRootTestObject().find(
			SubitemFactory.atDescendant(".class", "Html.SPAN",   
			".id","e-actions-mailview-inbox-new-text"));

Now, the .id property of an object is not available, so we can use the .text property to identify this object. The .text property will be translated into other languages in the native language build. It's not a fixed value and will display different values in different languages. We can use the unique ID (dwa1377) that is next to the New menu item to identify the object. This ID is fixed, and we can load the exact translation of the English string (New). Therefore, we can recognize the New menu item object. Listing 6 is code fragment to use for finding the object by the .text property.

Listing 6. Example of finding an object by the .text property
RationalTestScript.getRootTestObject().find(
    SubitemFactory.atDescendant(".class", "Html.SPAN",   
    ".text", Langfuncs.Instance().getLocalStringByID("dwa1377", "New")));

Step 6. Debug automation scripts in English and non-English environments

If we want to develop and debug our automation scripts in a pseudo-translated build, we must store pseudo-translated strings in a DWAMemory_en.properties file and set the DEBUG value to true. Pseudo-translated strings are displayed in a pseudo build, and our automation scripts recognize test objects in a pseudo build through the displayed strings (pseudo-translated) on the UI.

We also can debug our automation scripts in English environments or other translated environments. We strongly recommend that you debug them with double-byte or three-byte languages, such as Chinese, Japanese, and Thai.

This article subject to IBM's reservation of rights in copyright in the Article for internal use or promotional purposes, reservation of all other rights than copyright including the underlying information and portions.

Resources

Learn

Get products and technologies

  • Download a free trial version of Rational software.
  • Evaluate other IBM software in the way that suits you best: Download it for a trial, try it online, use it in a cloud environment, or spend a few hours in the SOA Sandbox learning how to implement service-oriented architecture efficiently.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Rational software on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational
ArticleID=857149
ArticleTitle=Multilingual automation testing solution
publish-date=02262013