Best practices in globalization: Developing IBM Lotus Notes applications

This article introduces the best practices in globalization that you can use to develop a good IBM®Lotus Notes® application. Following these recommendations, you can easily create good multilanguage-friendly Lotus Notes applications, which in turn can save you both resources and effort.

Share:

Tony Kuo (yjkuo@tw.ibm.com), Staff Software Engineer, IBM

Tony Kuo is a Staff Software Engineer at the IBM China Software Development Lab in Taipei, Taiwan. His areas of expertise include software globalization, globalization, and testing. He leads teams working on IBM Lotus Notes and Lotus Domino globalization and globalization verification testing. You can reach him at yjkuo@tw.ibm.com.



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

Wang Jun is a Software Engineer at the IBM China Software Development Lab in Beijing. He is the lead of the IBM Lotus Notes/Domino globalization template team and has rich experiences working with Lotus Notes template globalization.



29 June 2009 (First published 31 March 2009)

Also available in Chinese Russian

Editor's note: Know a lot about this topic? Want to share your expertise? Participate in the IBM Lotus software wiki program today.

Introduction

They say an ounce of prevention is worth a pound of cure. With many years of handling the Lotus Notes globalization task, we have identified where most of the Lotus Notes globalization issues occur: in the design and development phases. This article introduces the best practices in globalization that you can use to develop a good Lotus Notes application. Lotus Notes templates currently are translated into 27 languages, and this article presents the lessons that we learned in our years as Lotus Notes template developers and members of translation teams.

Globalizing Lotus Notes applications is a challenge for a lot of customers. The code and translatable strings of Lotus Notes applications are combined by their nature. Developers usually develop a Lotus Notes application in one language and impose the translation directly on the strings using IBM Lotus Domino® Designer client. As a result, hundreds of design elements need to be modified, language by language, whenever an application is changed or upgraded. Handling changes, managing version control, upgrading designs, and fixing problems all require a tremendous amount of effort.

This article is the second in a two-part series on globalization.

Part 1, "Helping customers globalize their IBM Lotus Notes applications," covers these topics:

  • The globalization process for Lotus Notes applications
  • The new features in version 8.5 of IBM Lotus Domino Global Workbench that use properties files for application globalization
  • Experiences with globalizing Lotus Notes applications and upgrading multiple language applications

Part 2, " Best practices in globalization: Developing a good IBM Lotus Notes application," covers these topics:

  • Lotus Notes application development guidelines for globalization consideration
  • Globalization consideration for various controls in Lotus Notes applications

This article can help you deliver high-quality Lotus Notes applications that meet globalization requirements. By following these best practices, you can avoid potential problems in the design and development stages, and you can save time and resources in the later software globalization stages.


How do I globalize my Lotus Notes application?

One common approach to developing an application in different languages is to develop the application in one language and then translate the resource files into other languages. This approach is called the single executable methodology. It has many benefits:

  • From the developer’s viewpoint, it’s easy to develop, test, and maintain.
  • From the user’s viewpoint, it’s simple to install and configure.

Figure 1 depicts the single executable codes module.

Figure 1. The single executable codes module
The single executable codes module

Due to the nature of the Lotus Notes template design, the template is a combination of terminology and code. Therefore, globalizing a Lotus Notes application is not easy for a lot of customers. There is neither an RC file (in which the translatable portions are enclosed in quotation marks) as in C/C++ applications, nor is there a property file (in which the translatable portions are preceded by an equals sign) as in Java™ applications in a Lotus Notes application. Usually, a Lotus Notes application is developed in the developers’ native language. After the design and development are completed, the applications are translated into other languages directly in the Lotus Domino Designer, a process that can involve modifications to the program codes.

Fortunately, we have Lotus Domino Global Workbench, which can help us to resource out the Lotus Notes’ strings and build the translated strings into applications in target languages. If you do not follow the globalization guidelines and best practices when developing a Lotus Notes application, though, problems inevitably emerge. Most globalization issues could be avoided from the beginning of your application design.

Figure 2 depicts the globalization application development life cycle. In this life cycle, globalization is involved in each phase of software development: user requirements, analysis and design, developing, testing, and maintenance.

Figure 2. The globalization application development life cycle
The globalization application development life cycle

As shown in the part highlighted in black in figure 2, best practices to develop globalization application is one of the most important sections in the life cycle. It can help you deliver high-quality Lotus Notes applications that meet the globalization requirements, comply with your organization's globalization guidelines, and pass the Globalization Verification Test.

This article introduces dozens of cases that we summarized from our years of Lotus Notes globalization practice, and most of these cases are easily ignored during the Lotus Notes application developing process. By following these recommended best practices, you can design and implement a good Lotus Notes application from the globalization perspective.


Avoid using concatenation strings in code

In the Lotus Notes application globalization process, concatenation strings are tagged in different terms in properties files and glossary databases. Because of this difference, it is difficult to ensure that these terms are combined correctly after translation.

In short, if the translated text is constructed just by concatenating the strings, the constructed sentences might no longer be grammatically correct in other languages. Listing 1 shows an example.

Listing 1. Code piece for using concatenation strings in a formula
@If(FirstDayOut = "" | FirstDayBack = ""; ""; "I will be out of the office starting  " 
+ @Text(@Date(FirstDayOut)) + " and will not return until " + 
@Text(@Date(FirstDayBack)) + ".")

The full sentence is not tagged into one term in the properties file if it contains the concatenation strings. Instead, the strings are tagged into separate terms without context. Listing 2 shows how the resourced-out properties look . Figure 3 and Figure 4 show you that the VAR2 and VAR4 won’t be resourced out.

In listing 2, the structure of the properties files is relatively simple: typically everything that follows an equals sign needs to be translated; everything that is preceded by a number sign (#) is to be excluded.

Listing 2. Resourced-out translatable terms
Form.(Out_Of_Office_Profile).Str1=I will be out of the office starting
Form.(Out_Of_Office_Profile).Str2=and will not  return until
Figure 3. Concatenation example - 1
Concatenation example - 1
Figure 4. Concatenation example - 2
Concatenation example - 2

When the separated strings are sent to a translator and translated into another language, the translator does not know whether they are displayed as one sentence on the user interface (UI). The separated terms are translated without context, and that fact can lead to obscurity or even misunderstanding. Sometimes, the concatenation strings have different combinations in different languages. The verb used in this string might not be used in another string due to differences in language or culture. The order of the sentences might need to be adjusted after translation.

Listing 3 depicts the proposed approach to avoid concatenation in your code; it shows one solution. In Listing 4, the separated strings have been resourced out as a whole sentence, which is much easier for the translator to understand and to translate.

Listing 3. The proposed approach to avoid using concatenation strings
@ReplaceSubstring("I will be out of the office starting var_startdate and 
will not return until var_returndate.";"var_startdate":"var_returndate"
:@Text(@Date(FirstDayOut)):@Text(@Date(FirstDayBack)))
Listing 4. Resourced-out translatable terms (correct example)
Form.(Out_Of_Office_Profile)_|_OutOfOfficeProfile.PostRecalc.Str1 = 
I will be out of the office starting var_startdate and will not return 
until var_returndate

Do not use translatable strings as programming conditions

Avoid the use of translatable strings as programming conditions is one of the most important guidelines to follow when you develop globalized Lotus Notes applications. Be sure to keep this warning in mind, because it is all too easy to forget.

Listing 5 shows an example that uses translatable strings as programming conditions.

Listing 5. Code snippets for using translatable strings as programming conditions
1. REM "Begin Do Not Translate"
2. Const DSPIND = "dspIndividualAccess"
3. REM "End Do Not Translate"

4. REM "Begin Translatable Text”
5. Const CALENDER_NOTICES = "Calendar notices are automatically 
forwarded to this person"
6. REM "End Translatable Text”

7. Set item = note.getfirstitem(DSPIND)
8. strIndividualAccess = item.Text
9. lposition = Instr( strIndividualAccess, CALENDER_NOTICES)
10. If lposition > 0 And lposition <> 1 Then
11.        ' strip off fwd msg
12.         strIndividualAccess = Left( strIndividualAccess, lposition-2 )		
13. Elseif lposition=1 Then 
14.          strIndividualAccess=""
15.  Else
16.          strIndividualAccess=Left( strindividualAccess, Len(strindividualAccess)-1)
17. End If

In listing 5, the program judges whether "dspIndividualAccess" is the substring of "Calendar notices are automatically forwarded to this person." Two separated properties are created with Lotus Domino Global Workbench. It’s hard to make sure that the first sentence is always translated as a subsentence of the second one if you are preparing to translate them into different languages. Figure 5 shows an example that translates them into simplified Chinese; in this example, the first sentence is not the subsentence of the second one.

Figure 5. Translation of two variables
Translation of two variables

Obviously functional issues can occur if these strings that have been used as programming conditions are translated. Furthermore, this sort of error is extremely difficult to track when you are globalizing your application. You should never use translatable strings as programming conditions. In addition to Instr in LotusScript®, which is often used to locate a substring, @UpperCase and @LowerCase in Formula, which are often used to uppercase or lowercase strings, table 1 shows some other functions in LotusScript and Formula that should not be used for translatable strings but to process non-translatable strings only. Processing translated character strings by these functions can cause unexpected results, such as bad translation words showing on the UI or functions failing.

Table 1. Functions in LotusScript and Formula to avoid in translatable strings
FunctionLotusScriptFormula
Covert Cstr, Cint, Cdat, Abstract, StrConv, Lcase, Ucase@LowerCase, @ProperCase, @LwerCase, @UpperCase, @TextToNumber, @TextToTime, @Explode, @Replace
Compare StrToken, StrCompare, Split, like@ReplaceSubstring, @Matches@Like, @Contains, ,
Length Mid, Len, LenC @Length
PositionLeft, StrLeft, StrLeftback, Right, StrRight, StrRightback, Instr, Trim, Contains, RightBP, MidBP@Left, @Middle, @Middleback, @Begins, @Ends, @LeftBack, @RightBack, @Right
Other Join…@Word…

Avoid using combinations of text and Lotus Notes fields on the user interface

Fields are often used in Lotus Notes for display (for example, text fields), but the incorrect use of these fields can lead to globalization problems. Mixing text and fields is also a concatenation issue, which can be similar to the issue we previously discussed.

When a message is translated into another language, the position and order of the substitution variables might have to change to meet the syntax requirements of the target language. Therefore, the software must avoid mixing text and fields, which might introduce grammatical errors to the translated strings. You must let the translators manage the position and order of the substitution variables and phrases.

Figure 6 shows a bad example; it’s a combination of text and Lotus Notes fields. The resourced-out translatable terms by Lotus Domino Global Workbench are shown in listing 8. Obviously, the whole sentence has been separated into different segments and is hard to translate.

Figure 6. A bad UI example
A bad UI example
Listing 8. Resourced-out translatable terms
Form.Response.Str1=The response is for
Form.Response.Str2=and was send by

As shown in figure 7, when we tried to translate this sentence into simplified Chinese, we found that the sentence structure is different from the English version, so the order of the fields might need to be changed as shown in figure 8.

Figure 7. Translate the whole sentence into simplified Chinese
Translate the whole sentence into simplified Chinese
Figure 8. Changing the order of the fields
Changing the order of the fields

It is impossible for the translator to change the order of the fields because the sentence has been split into more than one term in the properties file.

One of the solutions to avoid UI concatenation is to put these separated strings into one computed text or field and to use the variable to avoid the concatenation problems such as this: "The response is for VAR_Who1 and was send by VAR_Who2."


Add comments to your variables

You can add comments for these variables:

  • DNT variables
  • Hidden variables
  • Translatable variables

Add comments for DNT variables and hidden variables

DNT variables, which mean Do Not Translate, are important to translation. Hidden variables usually don’t need to be translated. It’s a good habit to add comments to them because doing so can help prevent their accidental translation. Listing 6 shows some good examples of adding comments for the DNT and hidden variables.

Listing 6. Add comments for DNT variables and hidden variables
1. DNT Variables in the LotusScript
REM "Begin Do Not Translate"
<LotusScript Code>
REM "End Do Not Translate"

2. DNT Variables in the Formula
'Begin Do Not Translate
REM {Begin Do Not Translate};
<Formula Code>
'End Do Not Translate
REM {End Do Not Translate};

3. Always hidden variables
'Begin Always Hidden variables
<Hidden variables>
'End Always Hidden variables

Add comments for translatable variables

Listing 7 shows an example of adding comments for translatable variables. In listing 7, the string order could be determined by the translator. Remember, these comments help translators to get to know what they are translating; keep in mind that most of the time, they do not see and understand the source code.

Listing 7. Add comments for translatable variables
{ REM The text of the next string determines the order of display of the 
following strings  "FamilyName" and "GivenName" }
OrderOfStings := "FamilyNameFirst";
Field1 := "FamilyName";
Field2 := "GivenName";

{ REM Begin DNT }
FIELD Display:=@If(OrderOfStrings = "FamilyNameFirst " ;Field1+Field2; Field2+Field1)
{ REM End DNT }

DGW will produce property file values that will look like this.
#  The text of the next string determines the order of display of the 
following strings  " FamilyName " and " GivenName "
Form.Memo.Action_Label_Formula.FamilyNameFirst =FamilyNameFirst
Form.Memo.Action_Label_Formula.FamilyName = FamilyName
Form.Memo.Action_Label_Formula.GivenName = GivenName

Tip: Naming DNT variable with a combination of uppercase and lowercase can help the translator to ignore them when translating. Listing 8 shows an example of DNT values named upDatEupdate and inForMation upDatE.

Listing 8. Naming the DNT variables with a combination of uppercase and lowercase
REM {Begin Do Not Translate};
update = "upDatE";
updateInformation = "inForMation upDatE";
requestInformation = "reQuesT InforMation";
requestupDate= "reQuesT upDate";
REM {End Do Not Translate};

Assign the strings to variables and define your variables correctly

There are a few key guidelines to remember when you assign strings to and define variables:

  • Never hard-code strings in code.
  • Define and assign variables only at the beginning of a script.
  • Do not use normal legible words to name internal variables.

Never hard-code strings in your code

In listing 9, the translatable strings are all hard-coded. The code in listing 9 is a bad example; this hard-coding makes make the code difficult to read, understand, and maintain, and also difficult for Lotus Domino Global Workbench to resource out. The better approach is to define the strings as variables in your code.

Listing 9. A bad example: Hard-coded strings in LotusScript
Function GetString(nIndex As Integer, vData As Variant) As String
  Select Case nIndex
  Case RECALL_STRING_MSGTO
    GetString = "Message to: "
  Case RECALL_STRING_MSGSTATUS
    GetString = "  Message status: "			
  Case RECALL_STRING_FAILREASON
    GetString = "  Recall failure reason: "			
  Case RECALL_STRING_NORESPONSES
    GetString = "Your recall request has been initiated.  
    For more information,
    open the Recall Status report for this 
    message when you receive it."					
  Case RECALL_STRING_OTHERREPORT
    GetString = "Other delivery reports. 
    (No recall information is available) "						
End Function

Listing 10 shows a good example of how to define strings as variables in the script. These messages are not hard-coded.

Listing 10. A good example: Defining variables instead of hard-coding the strings
Function GetString(nIndex As Integer, vData As Variant) As String
REM "Begin Translatable Text”
	Const xxMessage = "Message to: "
	Const xxMessageStatus = "  Message status: "
	Const xxMessageFailReason = "  Recall failure reason: "	
	Const xxMessageInitia= "Your recall request has been initiated.  
	For more information, open the Recall Status report for this message 
	when you receive it."	
	Const xxMessageOtherReport = "Other delivery reports. (No recall 
	information is available) "	
	REM "End Translatable Text”
	
	Select Case nIndex
	Case RECALL_STRING_MSGTO
		GetString = xxMessage
	Case RECALL_STRING_MSGSTATUS
		GetString = xxMessageStatus		
	Case RECALL_STRING_FAILREASON
		GetString = xxMessageFailReason		
	Case RECALL_STRING_NORESPONSES
		GetString = xxMessageInitia
	Case RECALL_STRING_OTHERREPORT
		GetString = xxMessageOtherReport
	End Select
End Function

Define and assign your variables only at the beginning of your script

In Listing 11, all the translatable and non-translatable strings have been defined at the beginning of the script, which makes the script easy to read.

Listing 11. Define the variables at the beginning of the script
REM "Begin Translatable Text”
Const xxRecipient = "Recipient"
Const xxStatus = "Status"
Const xxServer = "Server"
Const xxDetails = "Details"
Const xxNRecalled = "Not Recalled"
Const xxRecalled = "Recalled"
Const SERVER_NOT_SUPPORTED = "Server does not support Message Recall"
Const MESSAGE_NOT_FOUND ="Cannot find message.  
Server could be down or recipient no longer in NAB"
Const RECALL_REQUEST_NOT_FOUND = "Cannot process Recall Status report.  
Unable to locate Recall Request document."
Const INTERNET_RECALL_NOT_ALLOWED = "Cannot Recall from Internet Address"
REM "End Translatable Text”

REM "Begin Do Not Translate"
Const RECALL_ERROR = "Recall Error"
Const MAIL_RECALL_REQUEST_FORM$= "Recall Request"
Const MAIL_RECALL_RESPONSE_FORM$	= "Recall Response"
Const MAIL_TRACEREPORT_FORM$= "Trace Report"
Const MAIL_DELIVERYREPORT_FORM$= "Delivery Report"
Const MAIL_RETURNRECEIPT_FORM$= "Return Receipt"
Const SERVER_VERSION_NOT_SUPPORTED$="Pre-IBM Lotus Domino 8 Server"
REM "End Do Not Translate" 

Class ProcessRecall
	Public Sub Init(uidoc As notesuidocument)
		On Error Goto eTrap
		Dim uiws As New notesuiworkspace,session As New 
		NotesSession,reqSource As NotesUIDocument
……
……
		If (uidoc.InPreviewPane) Then
			Exit Sub
		End If		
		parentDocUNID = uidoc.Document.ParentDocumentUNID
		If (parentDocUNID = "") Then
			Msgbox RECALL_REQUEST_NOT_FOUND,16,RECALL_ERROR
			uidoc.close
			Exit Sub
……
……
	End Sub
End Class

Do not use normal legible words when naming internal variables

When naming internal variables, avoid using normal legible words. Instead, remove the space between two words to indicate to the translator that these compressed words are non-translatable variables. Listing 12 shows an example. Use InterestProfile instead of Interest Profile for the document name variable.

Listing 12. Don’t use normal legible words when naming your internal variables
Instead of:  @if(xxdocname = "Interest Profile";"Interest Profile";"Standard Document")
Try to use:  @if(xxdocname = "InterestProfile";"Interest Profile";"Standard Document")

Create the alias for the keyword of the option field

You must create an alias name for the keyword for programming consideration. The choices might display on the user interface, so you should add the alias name for the choices in the Listbox or Checkbox and then translate the strings that will display on UI, as shown in figure 9.

Figure 9. Listbox choices list
Listbox choices list

In figure 9, the choice follows the pattern shown in Meeting | Meeting: The first string is translatable because it’s used only for UI display, and the second string (the alias name) is not translatable. In properties files, only the latter translatable strings are resourced out for translation. Listing 13 shows what these resourced-out terms look like.

Listing 13. Resourced-out terms
Form.meeting.Listbox.MemoType = Meeting
Form.meeting.Listbox.MemoType = Appointment
Form.meeting.Listbox.MemoType = All Day Event
Form.meeting.Listbox.MemoType = Reminder
Form.meeting.Listbox.MemoType = To Do

Assign at least one alias name for the forms and views

The form name and view name usually need to be translated because they are visible, so adding the alias name is necessary for programming consideration.

Moreover, we suggest that the alias does not include spaces, especially if it might be used on the Web. Remember, the alias name is not translatable in the Lotus Notes application. Do not assign the same alias name for different design elements.


Use a table instead of the tab key to separate the static text from the field

Avoid using the tab key for layout control. In figure 10, the programmer is using the tab key to align the fields. The layout looks good in English, but after translation, the fields are not aligned because different terms might not be translated into terms of the same length. In figure 11, the layout is ineffective after the terms are translated into Korean.

Figure 10. Using tab key for layout control (English)
Using tab key for layout control (English)
Figure 11. Using tab key for layout control (Korean)
Using tab key for layout control (Korean)

Instead, use a table for layout control to separate the static text from the fields. The layout then is still clean, even after the terms are translated into other languages.


Decode and encode the variables that display on the Web

For the variables that display on the Web directly, remember to encode and decode them. In figure 12, the window title has been HTML encoded, but not decoded, so the %XX% garbage code displays in the title. Listing 14 shows you how to decode a variable.

Figure 12. Garbage code in window title
Garbage code in window title
Listing 14. Decode the variable
Example: PartialName := 
@Right(@URLDecode("Domino";Query_String);"&Title=")

Conclusion

In this article, the background and process of Lotus Notes application globalization have been introduced, and the related globalization tool, Lotus Domino Global Workbench. The globalization of Lotus Notes applications is done by extracting the translatable strings using Lotus Domino Global Workbench and rebuilding the translated strings into the original Lotus Notes applications.

Resources

Learn

Get products and technologies

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 IBM collaboration and social software on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Lotus
ArticleID=379231
ArticleTitle=Best practices in globalization: Developing IBM Lotus Notes applications
publish-date=06292009