z00bs
z00bs

Reputation: 7498

Passing parameters to i18n model within XML view

How can we pass parameters to the i18n model from within a XML view?

Without parameters

<Label text="{i18n>myKey}"/>

works but how can we pass a parameter in that expression?

The only piece of information I've found so far is http://scn.sap.com/thread/3586754. I really hope that this is not the proper way to do it since this looks more like a (ugly) hack to me.

Upvotes: 7

Views: 23059

Answers (6)

Tristan Storch
Tristan Storch

Reputation: 830

The trick is to use the formatter jQuery.sap.formatMessage like this

<Label text="{parts:['i18n>myKey', 'someModel>/someProperty'], 
                    formatter: 'jQuery.sap.formatMessage'}"/>

This will take the value /someProperty in the model someModel and just stick it in myKey of your i18n resource bundle.

Edit 2020-05-19: jQuery.sap.formatMessage is deprecated as of UI5 version 1.58. Please use sap/base/strings/formatMessage. See this answer on usage instructions.

Upvotes: 13

Pablo Silva
Pablo Silva

Reputation: 41

create file formatter.js

   sap.ui.define([
        "sap/base/strings/formatMessage"
    ], function (formatMessage) {
        "use strict";

        return {
            formatMessage: formatMessage
        };
    });

View

<headerContent>
            <m:MessageStrip
                text="{
                    parts: [
                        'i18n>systemSettingsLastLoginTitle',
                        'view>/currentUser',
                        'view>/lastLogin'
                    ],
                    formatter: '.formatter.formatMessage'
                }"
                type="Information"
                showIcon="true">
            </m:MessageStrip>
        </headerContent>

Controller

var oBundle = this.getModel("i18n").getResourceBundle();

MessageToast.show(this.formatter.formatMessage(oBundle.getText("systemSettingsLastLoginTitle"), "sInfo1", "sInfo2"));

i18n

systemSettingsLastLoginTitle=You are logged in as: {0}\nLast Login: {1}

Upvotes: 2

Matthias G&#252;nter
Matthias G&#252;nter

Reputation: 637

At the moment this is not possible. But you can use this simple workaround, that works for me.

Preparations

First of all we create a general i18n handler in our Component.js. We also create a JSONModel with a simple modification, so that immediatly the requested path is returned.

sap.ui.define([
    "sap/ui/core/UIComponent",
    "sap/ui/model/json/JSONModel"
], function(UIComponent, JSONModel) {
    "use strict";

    return UIComponent.extend("your namespace", {
        /**
         * Add a simple "StringReturnModel" to the components' models
         */
        init: function() {
            // [...] your other code in the init method

            // String Return Model
            var stringModel = new JSONModel({});
            stringModel.getProperty = function(sPath) {
                return sPath;
            };
            this.setModel(stringModel, "string");
        },

        /**
         * Reads out a string from our text domain.
         * The model i18n is defined in your manifest.json
         *
         * @param param text parameter
         * @param arr array for parameters
         * @return string
         */
        i18n: function(param, arr) {
            var oBundle = this.getModel("i18n").getResourceBundle();
            return oBundle.getText(param, arr);
        },
    });
});

Now, a model with the context {string>} exists. To use the i18n function in the XML view, we create a formatter function. This function parses the parts of the binding and returns the localized string.

sap.ui.define([
], function() {
    "use strict";

    var formatter = {
        /**
         * First argument must be the property key. The other
         * one are the parameters. If there are no parameters, the
         * function returns an empty string.
         * 
         * @return string The localized text
         */
        i18n: function() {
            var args = [].slice.call(arguments);
            if (args.length > 1) {
                var key = args.shift();
                // Get the component and execute the i18n function
                return this.getOwnerComponent().i18n(key, args);
            }
            return "";
        }
    };
    return formatter;
});

How To Use:

Together with the string-model you can use the formatter to pass paramaters to your i18n:

<Text text="{ parts: ['string>yourProperty', 'string/yourFirstParamter', 'anotherModel/yourSecondParamter'], formatter: '.model.formatter.i18n' }" />

You can pass how many paramaters as you want, but be sure that the first "part" is the property key.

Upvotes: 4

Breakpoint
Breakpoint

Reputation: 1541

As ugly as it may seem, the answer given in the link that you mentioned is the way to go. However it may seem complicated(read ugly), so let's break it down..

Hence, you can use the following for passing a single parameter,

<Label text="{path: 'someParameter', formatter: '.myOwnFormatter'}"/>

Here, the someParameter is a binding of a OData model attribute that has been bound to the whole page/control, as it is obvious that you wouldn't bind a "hardcoded" value in a productive scenario. However it does end with this, as you see there isn't a place for your i18n text. This is taken care in the controller.js

In your controller, add a controller method with the same formatter name,

myOwnFormatter : function(someParameter) { /* the 'someParameter' will be received in this function */ var i18n = this.i18nModel; /* However you can access the i18n model here*/ var sCompleteText = someParameter + " " + i18n.getText("myKey") /* Concatenate the way you need */ }

For passing multiple parameters,

Use,

<Label text="{parts:[{path : 'parameter1'}, {path :'parameter2'}], formatter : '.myOwnFormatter'}" />

And in your controller, receive these parameters,

myOwnFormatter : function(parameter1, parameter2) { } /* and so on.. */

When all this is done, the label's text would be displayed with the parameter and your i18n text.

Upvotes: 1

user2808624
user2808624

Reputation: 2530

In principle it is exactly as described in the above mentioned SCN-Link. You need a binding to the key of the resource bundle, and additional bindings to the values which should go into the parameters of the corresponding text. Finally all values found by these bindings must be somehow combined, for which you need to specify a formatter.

It can be a bit shortened, by omitting the path-prefix inside the array of bindings. Using the example from SCN, it also works as follows:

<Text text="{parts: ['i18n>PEC_to',
       'promoprocsteps>RetailPromotionSalesFromDate_E',
       'promoprocsteps>RetailPromotionSalesToDate_E'}], 
        formatter: 'retail.promn.promotioncockpit.utils.Formatter.formatDatesString'}"/>

Under the assumption, that you are using {0},{1} etc. as placeholders, a formatting function could look like the following (without any error handling and without special handling of Dates, as may be necessary in the SCN example):

formatTextWithParams : function(textWithPlaceholders, any_placeholders /*Just as marker*/) {
    var finalText = textWithPlaceholders;
    for (var i = 1; i < arguments.length; i++) {
        var argument = arguments[i];
        var placeholder = '{' + (i - 1) + '}';
        finalText = finalText.replace(placeholder, arguments[i]);
    }
    return finalText;
},

Upvotes: 0

aborjinik
aborjinik

Reputation: 753

What is written at the link is correct for complex formatting case. But if you want to combine two strings you can just write

<Label text="{i18n>myKey} Whatever"/> 
or
<Label text="{i18n>myKey1} {i18n>myKey2}"/>

Upvotes: 2

Related Questions