Localizing Error Messages

Objective

After completing this lesson, you will be able to provide localized error messages

Text Bundle Files

We use the req.error() method from the message API both in the implementation class for the AdminService from our scenario and in the implementation class for our CatalogService. We use this method to output error messages if validations fail. So far, we have hard-coded the reported messages as text literals.

In this lesson, we will learn how to internationalize messages. Instead of embedding them hard-coded, they are maintained in separate files - so-called text bundles - as key-value pairs. The keys are then used by the application code to access the corresponding texts. This means that the values for the keys are the actual language-specific texts. In order to support different languages, different files are maintained that provide translated texts for the same keys (see following figure). 

Creating Bundle Files for Internationalizing Error Messages

The detailed procedure is as follows: Create a file with the name messages.properties in a folder called _i18n, i18n or assets/i18n. The folder for the messages.properties file must either be located directly below the project directory or in a directory that contains files that are used to define service models (such as the srv directory in our project).

Note

The names of the folders in which CAP searches for text bundles can be configured in the package.json file of the project using the cds.i18n.folders property. By default, these are the folder names _18n, i18n and assets/i18n.

The required texts are maintained as key-value pairs in the messages.properties file. Usually, the texts are maintained there in English. Placeholders can be used, which are noted in the form "{n}". n runs through the natural numbers starting with 0.

To support additional languages, additional files are created in the same folder as the messages.properties file according to the following naming convention: messages<_languageCode><_countryCode>.properties. The country code is optional. Examples of such file names are messages_de.properties, messages_fr_CA.properties or messages_es_MX.properties.

The additional files use the same keys as the messages.properties file. However, the values for the keys are translated according to the language code and, if applicable, the country code from the file name.

In the example shown, two .properties files have been created: messages.properties with English texts and messages_de.properties with the corresponding German translations.

Fallback Chain

Assume that a text is queried via a key when processing a request, whereby German was determined for the language. If a text is maintained for the key in the messages_de.properties file, this text is used by the application. However, if there is no messages_de.properties file or the key used is not maintained in the existing messages_de.properties file, CAP falls back to the messages.properties file and attempts to determine a value for the key via this file. If this is possible, the corresponding text is used by the application. If messages.properties does not contain a matching entry either, the application uses the key name as text.

Note

The base name messages for the text bundles is mandatory. This means that the files created must be named as follows: messages<_languageCode><_countryCode>.properties. Technically, however, it is not necessary to create a raw file without suffixes with the name messages.properties. English texts can also be maintained in a file called messages_en.properties. In this case, however, you do not benefit from the fallback mechanism described above. This mechanism ensures that the texts from the messages.properties file are used if no .properties file has been created for a specific language or a specific key has not been maintained for a specific language in the related .properties file.

Accessing Localized Messages

The texts maintained in the text bundles can be accessed via the message API, for example via the methods req.error() or req.warn(). To do this, the corresponding key is simply passed to these methods instead of the actual message (see following figure).

Optionally, an array with placeholder values can be passed to the methods from the message API as last parameter. The first value from the array is then used for the placeholder {0}, the second value from the array for the placeholder {1} and so on.

Testing

You can use the URL parameter sap-locale to test different languages. In the following example, German texts are requested:

Code Snippet
1234567
POST <service_url>/submitOrder?sap-locale=de Content-Type: application/json { "book": "0ec991dc-95c5-4d8f-91e6-f81a92744781", "quantity": 0 }

Alternatively, you can also use requests with an appropriate Accept-Language header:

Code Snippet
12345678
POST <service_url>/submitOrder Accept-Language: de Content-Type: application/json { "book": "0ec991dc-95c5-4d8f-91e6-f81a92744781", "quantity": 0 }

The URL parameter sap-locale has the highest preference. It overrides the Accept-Language header if this should also be set.

Demonstration & Exercise: Use Localized Error Messages

Note

As exercise, carry out the step-by-step instructions in the following demonstration yourself in the SAP Business Application Studio.

As a starting point for the exercise, use the outcome of the previous exercise Use Queries in the Implementation of CAP Services if you have successfully completed it. Alternatively, you can also use the branch 14_queries from the following GitHub repository as a starting point:

https://github.com/SAP-samples/cap-development-learning-journey

The complete implementation of the simulation can be found in the 15_error_messages branch of the GitHub repository.

Detailed information on the content of the repository and how to use it can be found here.

Watch the video to see how to use localized error messages.

Log in to track your progress & complete quizzes