SAP / openui5

OpenUI5 lets you build enterprise-ready web applications, responsive to all devices, running on almost any browser of your choice.
http://openui5.org
Apache License 2.0
2.95k stars 1.23k forks source link

OpenUI5 doesn't catch "i18n_he.properties", only "i18n_iw.properties" for Hebrew #2891

Closed pubmikeb closed 4 years ago

pubmikeb commented 4 years ago

OpenUI5 version: 1.77.0

Steps to reproduce the problem:

  1. Set in Chrome (chrome://settings/languages) Hebrew as a priority # 1 in "Order languages based on your preference"
  2. In your UI5 app create i18n_he.properties
  3. Load the app

What is the expected result? UI5 will load i18n_he.properties

What happens instead? UI5 looks for i18n_iw.properties, can't find it and tries to load the priority # 2.

Any other information? (attach screenshot if possible) 25_173847

If I rename the i18n_he.properties to i18n_iw.properties everything is OK.

In Identifying the Language Code / Locale it's written that UI5 supports:

If so, then why UI5 expects iw instead of he for Hebrew?

codeworrior commented 4 years ago

Hi @pubmikeb,

this was indeed a problem for years. When we started UI5, our internal translation service provided an interface for the Java platform. Therefore, our ResourceBundle implementation took over the specifics of that platform, including the *.properties file format as well as the underscore in the language codes and, last but not least, the legacy ISO codes "in", "iw", "ji", "no" and "sh".

I'm sure this is documented somewhere, but I can't find it quickly (which obviously is a problem by itself).

Luckily, since 1.77, there's a solution for this and for other problems around localization. ResourceBundles (or more precisely, ResourceModels) that are declared in the manifest can now declare their set of supportedLocales. If this set contains "he", the framework knows that Hebrew should be loaded from the "messagebundle_he.properties" file, whereas when the list contains "iw", the framework will request "messagebundle_iw.properties" when the current language is Hebrew (no matter whether it is configured as "he" or "iw").

This list of supported locales also finally helps to avoid the 404s for "en_US" etc. when those locales don't exist in the backend. And it allows to configure the locales per bundle, which is important for bigger, componentized apps.

In 1.77, only the runtime mechanisms is present and can be used via manifest.json or via API. For future versions of the ui5-tooling, it is planned to fill the corresponding manifest entries automatically, based on the existing resources of a project.

More has been done regarding ResourceBundles and addtl. documentation will follow soon (hopefully).

HTH + Kind Regards

pubmikeb commented 4 years ago

@codeworrior, thanks for the detailed explanation! Great, now I realize how really important the Supported Locales and Fallback feature is. The description in What's New in OpenUI5 1.77 seems to be more theoretical, rather than applied.

codeworrior commented 4 years ago

The What's New section also names the addtl. stuff that I shortly mentioned: terminologies. They are a way of preparing a single app for different domain languages, something that SAP has to scope with in its industry solutions.

As I said, documentation hopefully will follow soon ("soon" in the usual meaning of "I don't know exactly when; not now, but somewhen later").

pubmikeb commented 4 years ago

@codeworrior, one more question regarding the supportedLocales and fallbackLocale features. I've tried to figure out how to use them, but it seems to not work out for me:

  1. In webapp/i18n I have two files:
    • i18n_en.properties
    • i18n_he.properties
  2. In manifest.json, into sap.app and sap.ui I've added the following code:
    "_version": "1.21.0",
    "sap.app": {
    "applicationVersion": {
        "version": "1.0.0"
    },
    "description": "{{appDescription}}",
    "i18n": {
        "bundleUrl": "i18n/i18n.properties",
        "fallbackLocale": "he",
        "supportedLocales": [
            "en",
            "he"
        ]
    },
    "id": "webapp",
    "title": "{{appTitle}}",
    "type": "application"
    },
  3. In Chrome, I've specified Hebrew as a primary language.
  4. I run my UI5 app and I expect to get an UI in Hebrew, but in fact the UI remains in English. Furthermore, if in Chrome I set German as the primary language, which my app doesn't have, I expect to get an UI in Hebrew, since "fallbackLocale": "he", but the UI remains in English as well.

Could you, please, point me how to make supportedLocales / fallbackLocale working? Thanks.

codeworrior commented 4 years ago

The bundle under "sap.app" / "i18n" is only used for the text placeholders within the manifest.json itself, not for the UI. For texts in the UI, you need to use a ResourceModel under "sap.ui5" / "models".

See this sample manifest for details. You should ignore the terminologies and enhanceWith properties.

pubmikeb commented 4 years ago

@codeworrior, thanks a lot.

supportedLocales and fallbackLocale inside of sap.ui5/models:

"_version": "1.21.0",
"sap.ui5": {
    "models": {
        "i18n": {
            "settings": {
                "bundleName": "webapp.i18n.i18n",
                "fallbackLocale": "he",
                "supportedLocales": [
                    "en",
                    "he"
                ]
            },
            "type": "sap.ui.model.resource.ResourceModel"
        }
    }
}

work, but with some exception — if fallbackLocale returns he, the text direction remains ltr instead of rtl. If I explicitly require he, then UI5 knows automatically apply rtl.

How to apply rtl in case the fallbackLocale language requires it?

pubmikeb commented 4 years ago

One more strange thing. I've specified "fallbackLocale": "he", in Chrome I set German as a favorite language, then I run the app and get Hebrew (although with a wrong text direction), but when I check the network, I still see that the app requires i18n_de.properties and downloads all available localisations:

26_095018

I've assumed that supportedLocales should eliminate the request of un-existing localization (i18n_de.properties) and fallbackLocale will ensure that in case the un-existing localization requested, the localization specified in fallbackLocale will be provided instead, and not all available localisations.

pubmikeb commented 4 years ago

I've also paid attention that "async": true in "sap.ui5"/"models"/"i18n"/"settings" leads to the problem, it doesn't allow to open a view, I get an error:

Uncaught TypeError: oBundle.getText is not a function
    at f.onBeforeRendering (WantedView.controller.js:113)
    at f.b.fireEvent (EventProvider-dbg.js:247)
    at f.d.fireEvent (Element-dbg.js:559)
    at f.fireBeforeRendering (ManagedObjectMetadata-dbg.js:781)
    at f.onBeforeRendering (View-dbg.js:646)
    at f.k.onBeforeRendering (XMLView-dbg.js:623)
    at f.d._handleEvent (Element-dbg.js:287)
    at Z (RenderManager-dbg.js:779)
    at Object.R.renderControl (RenderManager-dbg.js:900)
    at NavContainerRenderer-dbg.js:68

Once, I've removed "async": true, everything is working OK, despite that in some samples "async": true is used.

I've checked the documentation «Use Asynchronous Loading», there it's written:

To also load all application-specific configuration settings asynchronously, set the async property in the metadata of the manifest.json file to true:

"sap.ui5": {
"rootView": {
"viewName": "sap.ui.demo.worklist.view.App",
"type": "XML",
"async": true,
"id": "app"
}
}

@codeworrior, could you, please, provide some info, where exactly "async": true is required to ensure that 100% of my UI5 app is loaded asynchronously?

Thanks.

codeworrior commented 4 years ago

Reg." fallbackLocale": "he" and RTL: the fallbackLocale is a configuration per resource bundle whereas the RTL flag is a global thing in UI5. If one bundle falls back to "he", there still might be others (like SAPUI5's own bundles) that can handle "de").

There's no logic that would check whether all bundles fall back to "he" and then derive RTL from that. Basically, the fallbackLocale is not meant to redirect the logon language. It is rather a last resort during development when translation is not complete yet and when the text in an otherwise supported language has not been provided yet.

If you need a kind of global fallback for the login language, you better should validate the logon languages and set sap-language accordingly.

Reg. the requests ("en" and "he", despite limiting the fallbackLocale to "he"): that's indeed strange and should not happen. Without the complete manifest.json, I can only guess that the request for "en" came from some other place, e.g. from the "sap.app" bundle?

Reg. "async": using async for bootstrap (data-sap-ui-async), for the rootView and for the router (if any) is definitely recommended. Whether resource bundles for views need special treatment, I can't say out-of-the-box. I'll check that.

pubmikeb commented 4 years ago

There's no logic that would check whether all bundles fall back to "he" and then derive RTL from that.

Wow, I assumed, that there is a default rtl/ltr text direction property for any language, which is applied, unless is not explicitly overridden.

Reg. the requests ("en" and "he", despite limiting the fallbackLocale to "he"): that's indeed strange and should not happen. Without the complete manifest.json, I can only guess that the request for "en" came from some other place, e.g. from the "sap.app" bundle?

The entire manifest.json:

{
    "_version": "1.21.0",
    "sap.app": {
        "applicationVersion": {
            "version": "0.0.1"
        },
        "description": "{{appDescription}}",
        "i18n": "i18n/i18n.properties",
        "id": "webapp",
        "title": "{{appTitle}}",
        "type": "application"
    },
    "sap.ui": {
        "deviceTypes": {
            "desktop": true,
            "phone": true,
            "tablet": true
        },
        "technology": "UI5"
    },
    "sap.ui5": {
        "contentDensities": {
            "compact": true,
            "cozy": true
        },
        "dependencies": {
            "libs": {
                "sap.m": {}
            },
            "minUI5Version": "1.77"
        },
        "models": {
            "i18n": {
                "settings": {
                    "bundleName": "webapp.i18n.i18n",
                    "fallbackLocale": "he",
                    "supportedLocales": [
                        "en",
                        "he"
                    ]
                },
                "type": "sap.ui.model.resource.ResourceModel"
            }
        },
        "resources": {
            "css": [
                {
                    "uri": "css/general.css"
                }
            ]
        },
        "rootView": {
            "async": true,
            "id": "app",
            "type": "XML",
            "viewName": "webapp.view.App"
        },
        "routing": {
            "config": {
                "async": true,
                "bypassed": {
                    "target": "notFound"
                },
                "controlAggregation": "pages",
                "controlId": "app",
                "routerClass": "sap.m.routing.Router",
                "transition": "slide",
                "viewPath": "webapp.view",
                "viewType": "XML"
            },
            "routes": [],
            "targets": {}
        }
    }
}

The language-related properties are:

Here you may see what the app requires from the server. If "fallbackLocale": "he" is applied, then the OpenUI5 app downloads all available in supportedLocales localizations.

Perhaps, it's worth to note, here I'm talking about the OpenUI5 app, which doesn't have an SAP-backend.

codeworrior commented 4 years ago

Wow, I assumed, that there is a default rtl/ltr text direction property for any language, which is applied, unless is not explicitly overridden.

That's indeed the case, but for the sap-language (session language), not for each bundle that is loaded. And fallbackLocale even might be loaded in addition to, let's say, "de", just to get one of 99 text keys which hasn't been defined in the"de" file. It's a different concept of 'fallback' than what you imagined.

OpenUI5 app downloads all available in supportedLocales localizations.

The request for "en" occurs because "en" is the default fallback locale. Under "sap.app", you did not specify "he" as fallback, so "en" is requested (first request). The second request is for the model. If you use a different path under sap.app, e.g. "i18n/manifest.properties", you'll get the difference (not that you should do that in your app, just for illustrating the difference).

pubmikeb commented 4 years ago

Wow, thanks for detailed info.

Under "sap.app", you did not specify "he" as fallback, so "en" is requested (first request).

Do I understand it correctly, that to avoid of loading of extra i18n-files, I have to specify both fallbackLocale and supportedLocales not only under sap.ui5 / models / i18n / settings, but under sap.app as well?

codeworrior commented 4 years ago

To avoid extra-loading or 404s, configuring the supportedLocales usually is enough. The fallbackLocale only needs to be configured, if "en" (the default fallback locale) is not part of the supportedLocales or if you think that a language other than "en" fits better to look for texts that might be missing in the other text files.

Within SAP, we create texts first in the file without locale (we call that the "raw" locale) and we create them as English text. Obviously, that file therefore would be a natural candidate for the fallbackLocale. But after translation, "en" might be more appropriate for a native speaker and therefore we introduced another fallback "en" that is checked before the "raw" file. That's how fallbackLocale came into life.

Without any configuration, we would search the following sequence of files for a text (assuming the session language is "pt_BR"):

  pt_BR -> pt -> en -> raw locale

The search stops when a text is found.

BTW: if you don't need a fallbackLocale for missing text keys (because all properties files are complete or because text quality doesn't differ between locales), then you can also configure fallbackLocale="" and thereby skip the 3rd step above. Only makes a difference, if text files are not complete.

pubmikeb commented 4 years ago

@codeworrior, thanks again for your time and passion to share the knowledge.

To avoid extra-loading or 404s, configuring the supportedLocales usually is enough.

So, I've specified:

"fallbackLocale": "en",
"supportedLocales": [
    "en",
    "he"
],

in both sap.app and sap.ui5/models/i18n/settings, but still observe 404, when a client has any language beyond the scope of supportedLocales.

Besides that, I've paid attention that now I'm loading i18n_en.properties twice: 28_011711 which is not a case for https://openui5nightly.hana.ondemand.com/, for instance.

It looks like that in my case supportedLocales is not enough to prevent 404 and also for some reason i18n_en.properties appears twice in a logs.

Perhaps, it's worth to note, that as a backend I'm using Node.js 14 with Express.js.

codeworrior commented 4 years ago

From our conversation, I learn a lot about what needs to be documented :-)

Well, without knowing your app in full detail, all I can say is: the remaining 404s must be caused by bundles that are not configured in the manifest.json.

Do you use bundles that are configured in XML views? Or create some via API calls? The Initiator column in Chrome's network tab might reveal what code loads the bundle.

pubmikeb commented 4 years ago

From our conversation, I learn a lot about what needs to be documented :-)

Indeed. Actually, the UI5 documentation is fairly good, the real problem is its verbosity, accompanied by a poor built-in search engine, which makes it quite difficult/time consuming to find something specific. Real-world example, try to find information regarding the accordance of _version inside of the app manifest to the UI5 version with built-in search and with Google.

Do you use bundles that are configured in XML views?

No, as far as I know. At least the code of the XML-template for the initial login view is quite plain:

<core:View xmlns:core = "sap.ui.core"
           xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
           xmlns = "sap.m"
           controllerName = "app.controller.Login"
           xsi:schemaLocation = "sap.ui.core ">

    <Page title = "{i18n>loginPageTitle}">
        <content>
            <Panel headerText = "{i18n>loginPageText}" expandable = "true" expanded = "true">
                <content>
                    <Input id = "userID" value = "{/login}" placeholder = "Username" change = "onChanged" />
                    <Input type = "Password" id = "pwd" placeholder = "Password" change = "onChanged" />
                    <Button text = "Login" press = "btnClicked" />
                </content>
            </Panel>
        </content>
    </Page>
</core:View>

The Initiator column in Chrome's network tab might reveal what code loads the bundle.

I've checked the initiator value: 03_183221 It looks like the missed file is required by sap-ui-core.js via jQuery: 03_183435

Perhaps, in addition to supportedLocales there is some extra meta-parameter in manifest, which I forgot to specify to avoid requesting something, which is not mentioned in supportedLocales?

@codeworrior, thanks for your support, I really appreciate and learn a lot from such a direct contact!

tobiasso85 commented 4 years ago

Hi @pubmikeb , the supportedLocales is the property for filtering and defines what are valid locales for properties files to be requested. If supportedLocales is configured in your manifest for both: sap.app / i18n and sap.ui5 / models / i18n / settings there should be no request for locale en_US

The stacktrace is triggered by the manifest loading.

see also: https://blogs.sap.com/2020/06/03/ui5ers-buzz-54-i18n-with-supportedlocales-and-fallbacklocale-configuration/

pubmikeb commented 4 years ago

Hi @tobiasso85,

thanks for the link, it helped me a lot! The following solved my issue:

With manifest version 1.21.0 the sap.app i18n section can hold an object containing bundleUrl, supportedLocales and fallbackLocale.

The general problem with the UI5 documentation is that from one point of view it's so detailed, and from another it lacks some critical info and samples, or they a burred somewhere so deep, so you can find them only if you know exactly what you are looking for, e.g. explanation about manifest version and a table with UI5 library version vs. manifest version.

For instance, in the Supported Locales and Fallback article there is no mention regarding a new structure of i18n section and no sample for sap.app, there is only sample for sap.ui5:

"i18n": {
  "bundleUrl": "i18n/i18n.properties",
  "supportedLocales": ["en", "de"],
  "fallbackLocale": "en"
},

Ideally, it should explain what is an expected structure for i18n in both sap.ui5 and sap.app.

Besides that, there is no any information what's the difference between sap.ui5 and sap.app in terms of i18n configuration.

P.S. Please, consider reviewing the UI5 JSON schemas and updating them if needed (https://github.com/SAP/openui5/issues/2943).

flovogt commented 4 years ago

Hi @pubmikeb , thanks a lot for reporting back that you were able to solve the issue. Your hints regarding the documentation will be considered in one of the following releases. With that I'll close the ticket. Best Regards, Florian