Reputation: 7498
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
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
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
Reputation: 637
At the moment this is not possible. But you can use this simple workaround, that works for me.
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;
});
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
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
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
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