Translation with the SmartComponent Library
In a globalized markets today’s applications are typically not only developed for an audience from a single nationality – having the application enabled for localization is often a key requirement for ensuring chances on the market. Thus a user interface capable of multiple-languages is more important than ever. The SmartComponent Library supports you with a series of features to have a fully translatable UI right from the start with almost no extra effort. In detail the UI is translatable via .NET resource files, application messages are stored in multiple languages in a database table and the framework is also capable of translating common strings beyond that.
UI translation via resource file (.resx)
The standard translation approach for .NET Applications is to use a set of translated resource files for each Form and UserControl. Compared to other translation techniques the resource files ensure, that the vendor of the Controls you are using (e. g. Infragistics or Microsoft) has defined which strings and other properties (like Images) of the components are to be translated. Any other translation technique would require that you make this decision yourself for every control. Furthermore the translation using the resource files is plugged right into the InitializeComponents method of the Forms or UserControls built in the Visual Designer offering the best possible performance.
To make this feature available in your development environment, the developer will have to set the “Localizable” property of each Form and UserControl to true. After doing this, all the translatable strings will be written to and read from the resource file by the Visual Designer. The SmartFramework provides for the actual user interface translation in the Form “Resource Translation Maintenance”. In the maintenance form a user can select a Form or a UserControl (e. g. Viewer) to be translated. The current user interface language of the user will be used as the target language. The translations are by default stored in the SmartDB. The translated resx files could then be generated on the client when needed or could be generated by the application vendor and shipped as part of the application code base.
Message translation
To implement multi language messages the SmartFramework supports you by storing message texts in the SmartDB organized by type (info, warning, question), group (logical ordering) and a number for each message (defined by yourself). Messages are stored for a defined language or as the default language. You can provide a short text and a message detail which can use &1 … &9 as place holder to include additional information during runtime (ABL SUBSTITUTE function). Messages are maintained in the “Message Maintenance” form.
The strings defined here can now be used inside the application using the MessageProvider class. This class returns the message in the current user language or the default.
DEFINE VARIABLE oMessageProvider AS Consultingwerk.SmartFramework.IMessageProvider NO-UNDO . DEFINE VARIABLE oMessage AS Consultingwerk.SmartFramework.Message NO-UNDO . /* get reference to the Message Provider Service */ oMessageProvider = {Consultingwerk/get-service.i Consultingwerk.SmartFramework.IMessageProvider} . /* get the message structure with 0 to 9 message parameters substituted */ oMessage = oMessageProvider:GetMessage ("SFR":U, 1, "Hello World":U) .
In the sample code you see the definition of two variables. oMessageProvider of type Consultingwerk.SmartFramework.IMessageProvider is set to the running instance of the service returned by the function Consultingwerk/get-service.i. These services are typically loaded on startup of the application using the SmartComponent Library. oMessage is of type Consultingwerk.SmartFramework.Message and is set to the returned message retrieved by calling the GetMessage method of the MessageProvider. As mentioned above, the call can contain 0 up to 9 additional strings for a substitute statement.
METHOD PUBLIC Message GetMessage (pcMessageGroup AS CHARACTER, piMessageNumber AS INTEGER): METHOD PUBLIC Message GetMessage (pcMessageGroup AS CHARACTER, piMessageNumber AS INTEGER, pcParameter1 AS CHARACTER):
For the message to be displayed you will need to use the following statement within your code:
Consultingwerk.Util.MessageFormHelper:ShowMessage (oMessage) .
When displaying questions you will need to enhance the call to deal with the answer as shown below:
IF Consultingwerk.Util.MessageFormHelper:ShowMessage (oMessage) = Consultingwerk.Framework.Enum.DialogResultEnum:DialogResultYes THEN DO: /* yes branch */ END. ELSE DO: /* no branch */ END.
Message Translation in business logic (backend) validation code
When performing validation on the backend you will typically also be generating messages to be displayed to the user and these should also be translated. The messages are stored using the same maintenance program as the UI messages from the previous section. The following code shows how to retrieve a message and add additional information in a substitution with again up to 9 values.
Consultingwerk.SmartFramework.MessageFormatter:GetMessage ("VALMSG":U, 1, "Customer Name") .
For more information about validation see http://confluence.consultingwerkcloud.com/wiki/display/SCL/Business+Entity+Validation+made+easy
The message formatted API does not access the localizations on the backend (AppServer). The message formatter simply returns the message code and all parameters (SUBSTITUTE) in a standardized form to the client where messages are translated in the ErrorHelper by calling into the Consultingwerk.SmartFramework.IMessageProvider service and thus allowing a local cache of translated messages.
Translation of common strings
The translation of common strings allows to translate for example calculated field values or other strings that are generator from your code. For this purpose the SmartComponent Library provides the include file translate.i to make the usage of the API as easy as possible.
Translation of common strings are maintained in the "Translation Maintenance" form and can either be in the form of an orignal string (typically English) to a localized stirng or from a key to a localized string. All translations are stored within a translation scope. When translating based on keys, the original applicaiton language requires records in the translation maintenance as well.
The possible ways of using the translate.i to retrieve translations include are the following:
Static String: {Consultingwerk/translate.i &scope="''" &string="'Question':U"} Variable: {Consultingwerk/translate.i &scope=cScope &string=cString} No scope: {Consultingwerk/translate.i &string="'Question':U"} By key: {Consultingwerk/translate.i &scope="''" &key="'xyz':U"}
The scope of the translation is a logical grouping of strings.
One usecase is for instance when dynamically creating a ribbon group or a tab or similar user interface components. For this we need a key and a caption. The following sample shows how the variables can be initialized, assuming that the variables are defined as CHARACTER. The sample is running in the scope ‘Attachment’ and tries to translate the string ‘Attachments’.
ASSIGN cCaption = {Consultingwerk/translate.i &scope="'Attachment':U" &string="'Attachments':U"}.