Merging Two I18n Text Bundles

Often when working on a suite of applications you will want to encapsulate common code into reusable libraries and or components. Inside of the reusable module is a master text file, a requirement that has popped up a few times is how to merge the master text file with the translatable text file the applicaiton uses.

Below i show how its possible to merge an application i18n models texts with the texts from a reusable components i18n model.

Why would you want to do it? you are creating a suite of Sales and Distribution applications for end users, there is a common buiness vocabulary that you may want to share between applications.

The pic below shows a reusable component, later it will be loaded as a dependency in an application, in this simple example i am creating one text property which will be merged.

In the manifest we ensure the i18n model is loaded when the component is instantiated.

"models": {
    "i18n": {
        "type": "sap.ui.model.resource.ResourceModel",
        "uri": "i18n/i18n.properties"
    }
},

Next create an application which also has a single text property

To demonstrate successful merge of texts we declare a simple view which shows the two text properties.

<mvc:View controllerName="test.reuse.myApp.controller.Main" 
xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc">
    <Button text="{i18n>myAppText}"/>
    <Button text="{i18n>commonText}"/>
</mvc:View>

To consume the common component from an application, inside the manifest under “dependencies” declare the reusable component.

"sap.ui5": {
    "rootView": "test.reuse.myApp.view.Main",
    "dependencies": {
        "minUI5Version": "1.32.1",
        "components": {
            "test.reuse.common": {
                "minVersion": "1.0.0"
            }
        }
    },
    "models": {
        "i18n": {
            "type": "sap.ui.model.resource.ResourceModel",
            "uri": "i18n/i18n.properties"
        }
    },

In the example below the Component is saved as a BSP in the ABAP UI5 Repository, so at the top of the Component file we need to the following

var sUrl;
jQuery.sap.registerModulePath("test.reuse.common", {
    url: "/sap/bc/ui5_ui5/sap/zcommon"
});

Originally had this logic in the manifest “resoureRoots” but later found that absolute paths cannot be entered

If you are like me and developing in teams where members use both WebIde and thier own local development environment, you will want to overide the destination defined in the resource root and point to both local server resources and the cloud based workspace where the common component is located. In WebIDE this is similar to how you would reference the source application from an extension project.

When registeing a module path if you set the “final” flag to true then any subsequent path registration will be ignored.

var sUrl;
if (window.location.host.match(/^(localhost|127.0.0.1|0.0.0.0)/)) {
    sUrl = "../common";
} else if (window.location.host.match(/(<TENANT>)/)) {
    sUrl = "/../orion/file/<TENANT>$<USERID>-OrionContent/common/";
}

jQuery.sap.registerModulePath("test.reuse.common", {
    url: sUrl,
    final: true
});

Don’t forget to add the “neo-app.json” entries for the backend and orion paths for WebIDE.

{
    "path": "/orion/",
    "target": {
        "type": "service",
        "name": "orion",
        "preferLocal": true
    },
    "description": "Orion Server"
}, {
    "path": "/sap/bc/ui5_ui5/sap/",
    "target": {
        "type": "destination",
        "name": "abap",
        "entryPath": "/sap/bc/ui5_ui5/sap/"
    },
    "description": "Gateway Server"
}

So we have created a reusable component with a common translatable text file, added it as a dependency to our application, coded options for finding the Component when running locally and from a server, all that is left is to get an instance of the reuse component and merge the i18n models, we do that in the applications component.

jQuery.sap.registerModulePath("test.reuse.common", {
    url: "/sap/bc/ui5_ui5/sap/zcommon"
});

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

        return UIComponent.extend("test.reuse.myApp.Component", {
            metadata: {
                "manifest": "json"
            },

            init: function() {
                // get the i18n model for the app
                var oI18nModel = this.getModel("i18n");

                // get the common component
                var oCommonComponent = sap.ui.component({
                    name: "test.reuse.common"
                });

                // get the common component resource bundle
                if (oCommonComponent) {
                    var oBundle = oCommonComponent.getModel("i18n").getResourceBundle();

                    // enhance the app i18n with the resources from the commmon component
                    oI18nModel.enhance(oBundle);
                }
                // call the init function of the parent
                UIComponent.prototype.init.apply(this, arguments);
            }
        });
    });

Then when we run the application, the two texts are merged into one model

Comments