Skip to Content

SAP UI5: i18n for each view

Quite recently, I dove into SAP UI5 development. To educate myself, I followed a workshop and I used the Walkthrough.

During my explorations, I ran into a particular issue which I didn’t see very readily addressed. I also found a solution for this particular issue, and even though I still have a ton to learn, I think it is worth sharing here on scn.

So, here goes:

The Feature: Translatable texts and the i18n model

One of the SAP UI5 features highlighted in the Walkthrough is treatment of translatable texts. In the walkthrough this is realized by setting up a resource model, the i18n model.

The i18n model is sourced form i18n .properties files, which are essentially lists of key/value pairs, one per line, and separated by an equals sign:

greetingAction=Say Hello
greeting=Hello {0}!

To actually setup a i18n model using these texts, you can explicitly instantiate a sap.ui.model.resource.ResourceModel:


], function(Controller, ResourceModel){
    "use strict";
    return Controller.extend("", {
        onInit: function(){
            var i18nModel = new ResourceModel({
                bundleName: ""
            this.getView().setModel(i18nModel, "i18n")

Or, you can have your application instantiate the model by listing it in the models property of the sap.ui5 entry in the  manifest.json application descriptor file:


"models": {
  "i18n": {
    "type": "sap.ui.model.resource.ResourceModel",
    "settings": {
    "bundleName": ""

In many cases, the text is required for the static labels of ui elements like input fields, menus and so on. Inside a view, static texts may be retrieved from the i18n model through special data binding syntax, like so:

<Button text="{i18n>greetingAction}"/>

Texts may also be retrieved programmatically inside controller code by calling the .getText() getter on the resource bundle object. The resource bundle which may be obtained from the ResourceModel object using the .getResourceBundle() getter:

var bundle = this.getModel("i18n").getResourceBundle();
var text = bundle.getText("greeting", ["World"]);

Now, the cool thing is that you can write a separate i18n .properties file for each locale that you want to support. The framework discovers which locale is required by the client and use that to find the best matching i18n .properties files appropriate for the client’s locale.

The file name is used to identify to which language and/or locale the texts inside the file apply. For example, you’d put the German texts in a file, and the English texts in a file, and if you want to distinguish between British and American English, you’d create both a and file.

(I haven’t found out to exactly which standard the sap ui i18n .properties files apply, but from what I’ve seen so far I think it’s safe to assume that you can use the two-letter lowercase ISO 639-1 code for the language and the two-letter uppercase ISO 3166-1 code for the country)

The Problem: One i18n Model for entire application

Now, the walkthrough demonstrates the feature by adding one i18n model for the entire application so that it becomes available in any of the views that make up the application. I appreciate that the walkthrough is not the right place to cover all kinds of more advanced scenarios, so I can understand why it settles for just one application-wide i18n model.

However, I can’t help but feeling this is not an ideal approach. Main reason is that it seems at odds with the fact that many texts are specific to just one particular view. This challenges both the development workflow as well as the reusability of our application components:


  • Each time you create or modify a particular view, you also have to edit the global i18n files. To keep things manageable, you will probably invent some kind of view-specific prefix to prefix the keys pertaining to that view, and you’ll probably end up creating a view-specific block in that i18n file. At some point, you’ll end up with a lot of lines per i18n file, which is not so maintainable
  • Suppose you want to reuse a particular view in another application. Contrary to the practice used in the Walthrough, I like to keep view and associated Controller together, and in a folder separate from any other view and controller. This way I can easily copy, move or remove the things that belong together. Except that the texts, which also belong to that view/controller, are in the global i18n properties file, and need to be managed separately.

The Solution: Keep per-view i18n files near view and controller code

The solution I found is to create a i18n subfolder beneath the folder that contains my Controller and View. Since I already keep each associated view and controller together, and separate from the other views and controllers, this approach makes sense: It’s just one step further in keeping code and resources that depend directly on each other physically together.

So, this is what my file and folder structure looks like:


So, the webapp folder is the root of the sap ui5 project. The components folder is where I keep subfolders for each functional unit (i.e. View+Controller+resources) of the application. In the picture, you see two such subfolders, basecontroller (more about that below) and mainpanel.

The mainpanel folder is the one that contains an actual component of my application – a MainPanel View, and its MainPanel controller. Here we also find the i18n folder specific to this view, and inside are the i18n .properties files (one for each locale).

In order to load and apply the view-specific i18n files, I’m using generic extension of sap.ui.core.mvc.Controller which loads the “local”, view-specific i18n resource bundle. This is what’s in the basecontroller folder, and it looks like this:

], function(Controller, ResourceModel){
  "use strict";
  var controller = Controller.extend("", {
    onInit: function(){
    _initI18n: function(){
      var i18n = "i18n";
      //create bundle descriptor for this controllers i18n resource data
      var metadata = this.getMetadata(this);
      var nameParts = metadata.getName().split(".");
      var bundleData = {bundleName: nameParts.join(".")};
      //Use the bundledata to create or enhance the i18n model
      var i18nModel = this.getModel(i18n);
      if (i18nModel) {
      else {
        i18nModel = new ResourceModel(bundleData);
      //set this i18n model.
      this.setModel(i18nModel, i18n);
    getModel: function(modelname){
      var view = this.getView();
      var model = view.getModel.apply(view, arguments);
      if (!model) {
        var ownerComponent = this.getOwnerComponent();
        if (ownerComponent) {
          model = ownerComponent.getModel(modelname);
      return model;
    setModel: function(model, modelName){
      var view = this.getView();
      view.setModel.apply(view, arguments);
  return controller;

Note how the BaseController initializes the i18 model by calling the _init118n() method. In this method we extract the className of the this object from its metadata (using the .getName() getter on the metadata obtained using the .getMetadata() getter), and we pop off the unqualified classname to obtain its namespace. We then add the string "i18n" twice – once for the folder, and once for the files inside it. We use this to create the bundlename which we use to instantiate the actual ResourceModel.

Before setting that model to the controller’s view, we check if there is already an i18n model set using getModel(). This is a utility method that gets the model from this controller’s associated view, or of the component that “owns” the view and this controller.

If a i18n model is already available, we enhance that by calling the .enhance() method on it, rather than replacing it. This way, any texts defined at a higher level are still available in this controller and view. This gives us a functional i18n model, which we then set using setModel(), which simply calls setModel() on the view associated with this controller.

To actually use the BaseController, we extend it when creating a “real” controller:

], function(Controller){
  "use strict";
  var controller = Controller.extend("", {
onInit: function(){;
  return controller;

Note that if that real controller has its own onInit() method, we need to first call the onInit() method of the base controller, or rather, of whatever class we’re extending. Fortunately, since we are extending it we already have a reference to it (in the snippet above, it’s the Controller parameter injected into our definition), so we call its onInit() method via the prototype while using the controller that is currently being defined (this) as scope.

Addendum for Nested Views

It turns out that this solution does not work completely for nested views. Fortunately, only a small improvement is required to make it work under these circumstances. The details of that particular issue are described in a separate post: SAP UI5: Internationalization for each view – Addendum for Nested Views


I hope you enjoyed this article! I hope it will be of use to you. If you have an alternative solution – quite possiby, a better one – then please feel free to leave a comment and point out your solution. I’m eager to hear and learn so don’t hesitate to share your opinion and point of view.

You must be Logged on to comment or reply to a post.
  • Sorry not reading your article, seems very interesting indeed. Anyway, I found a typo error in the fourth example (it's missing the closing bracket } in the button text before the closing quote):

    <Button text="{i18n>greetingAction"/>


  • Hi Roland Bouman,


    Great Blog, very helpful, and i have small question, is there any way to update the value in a property file to update the value from the controller?


    Thanks in advance,


    • Hi Pradeep,


      thanks for you interest!
      (Please check out the latest article on sapui5 and i18n I wrote here:

      > is there any way to update the value in a property file to update the value from the controller?

      I don't think so - how could there be? The i18n is a file on the server side. It would be a bad idea if the browser could update that.

      What you can do though is have the controller manipulate the i18n model. Then the chance will be available inside your application at runtime.

      If you really do want the application to update the i18n data, then I suggest you use an OData service for your properties.

      Your application can then use an OData model to update the properties. In order to use them in a i18n model in the usual way, you would do a read request on your ODatamodel to fetch all properties, and then instantiate or update a sap ui5 i18n model from that data.

      I haven't tried it myself, but this is the approach I would be investigating.

      I hope this helps,

      Best regards,


  • Interesting thoughts. I am wondering, conversely, that if there are a lot of text that are used across a lot of apps, would it be more productive to define them once in an i18n library and load them all from there.

    Would the benefits of having defined everything once be overcome by the size of the file.

    Does anyone have any stats on the performance of larger i18n files?




    • Valid considerations. I would  guess that in general, from a web-app performance point of view it would in most practical cases be faster to load just one file. Per-view i18n is more about managing components in a more OO manner.

      Ideally, the deployed webapp would read just one i18n file. So one would have create a build task that can bunch up all the per-view i18n files, as well as some setting in say the manifest that all controllers know about to suppress per-view i18n loading. I haven't gone so far as to develop those though.

      • maybe ... and I am thinking out loud here that a build step could be to consolidate all i18n files into one ...


        ... or maybe not.


        Food for thought though thanks for responding.


  • Hi Roland Bouman,

    Interesting blog on i18n for each view.

    I have a doubt here.

    Can we retrieve the i18n from a single backend service and share it across different SAPUI5 applications?  Is it a good idea to store the i18n files separately in the backend services as we would like to share the text across different SAPUI5 applications?


    “”: {
    “id”: “”,
    “type”: “application”,
    “i18n”: “i18n/”,
    “title”: “{{appTitle}}”,
    “description”: “{{appDescription}}”,
    “applicationVersion”: {
    “version”: “1.0.0”

    “models”: {
    “i18n”: {
    “type”: “sap.ui.model.resource.ResourceModel”,
    “settings”: {
    “bundleName”: “”


    Above are the implementation for getting the i18n model in manifest.json.

    e.g webapp/i18n/

    If i would like to retrieve i18n model from a backend service instead of storing it at the project folder. how shall i implement it?


    Thank you!


    • Can we retrieve the i18n from a single backend service and share it across different SAPUI5 applications?


      Sure, just store your i18n .properties file some place and make sure it can be retrieved with HTTP. Then use the same url across different models. To avoid cross-domain restrictions, either make sure the app and i18n are served from the same host+port, or set up cors headers on the server to allow it (this might need some tweaking on the model instantiation side, not sure, never tried it)