Skip to content

Commit abfb221

Browse files
authored
feat: inline english texts if no translation is fetched (#479)
1 parent 2261f1c commit abfb221

File tree

8 files changed

+83
-48
lines changed

8 files changed

+83
-48
lines changed

packages/base/src/ResourceBundle.js

+33-32
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,11 @@
11
import "./shims/jquery-shim.js";
22
import ResourceBundle from "@ui5/webcomponents-core/dist/sap/base/i18n/ResourceBundle.js";
3+
import formatMessage from "@ui5/webcomponents-core/dist/sap/base/strings/formatMessage.js";
34
import { getLanguage } from "./LocaleProvider.js";
45
import { registerModuleContent } from "./ResourceLoaderOverrides.js";
56
import { fetchJsonOnce } from "./util/FetchHelper.js";
67

78
const bundleURLs = new Map();
8-
const singletonPromises = new Map();
9-
10-
/**
11-
* Creates a new promise for the specified key (or returns a new one and stores it for next calls).
12-
* The same promise is always returned for multiple calls to this method for the same key.
13-
* This promise can also be resolved so that all usages that await its resolution can continue.
14-
* @param {key} key the unique key identifying the promise
15-
* @private
16-
*/
17-
const _getSingletonPromise = key => {
18-
const prevPromise = singletonPromises.get(key);
19-
if (prevPromise) {
20-
return prevPromise;
21-
}
22-
23-
let resolveFn;
24-
const newPromise = new Promise(resolve => {
25-
resolveFn = resolve;
26-
});
27-
// private usage for making a deferred-like API to avoid storing resolve functions in a second map
28-
newPromise._deferredResolve = resolveFn;
29-
30-
singletonPromises.set(key, newPromise);
31-
return newPromise;
32-
};
339

3410
/**
3511
* This method preforms the asyncronous task of fething the actual text resources. It will fetch
@@ -41,10 +17,14 @@ const _getSingletonPromise = key => {
4117
* @public
4218
*/
4319
const fetchResourceBundle = async packageId => {
44-
// depending on the module resolution order, the fetch might run before the bundle URLs are registered - sync them here
45-
await _getSingletonPromise(packageId);
4620
const bundlesForPackage = bundleURLs.get(packageId);
4721

22+
if (!bundlesForPackage) {
23+
console.warn(`Message bundle assets are not configured. Falling back to english texts.`, /* eslint-disable-line */
24+
` You need to import @ui5/webcomponents/dist/MessageBundleAssets.js with a build tool that supports JSON imports.`); /* eslint-disable-line */
25+
return;
26+
}
27+
4828
const language = getLanguage();
4929

5030
let localeId = ResourceBundle.__normalize(language);
@@ -72,13 +52,34 @@ const fetchResourceBundle = async packageId => {
7252
*/
7353
const registerMessageBundles = (packageId, bundlesMap) => {
7454
bundleURLs.set(packageId, bundlesMap);
75-
_getSingletonPromise(packageId)._deferredResolve();
7655
};
7756

78-
const getResourceBundle = library => {
79-
return ResourceBundle.create({
80-
url: `${library}.properties`,
81-
});
57+
class ResourceBundleFallback {
58+
getText(textObj, ...params) {
59+
return formatMessage(textObj.defaultText, params);
60+
}
61+
}
62+
63+
class ResourceBundleWrapper {
64+
constructor(resouceBundle) {
65+
this._resourceBundle = resouceBundle;
66+
}
67+
68+
getText(textObj, ...params) {
69+
return this._resourceBundle.getText(textObj.key, ...params);
70+
}
71+
}
72+
73+
const getResourceBundle = packageId => {
74+
const bundleLoaded = bundleURLs.has(packageId);
75+
76+
if (bundleLoaded) {
77+
return new ResourceBundleWrapper(ResourceBundle.create({
78+
url: `${packageId}.properties`,
79+
}));
80+
}
81+
82+
return new ResourceBundleFallback();
8283
};
8384

8485
export { fetchResourceBundle, registerMessageBundles, getResourceBundle };

packages/main/bundle.esm.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import "@ui5/webcomponents-base/src/browsersupport/Edge.js";
44
import "@ui5/webcomponents-base/src/shims/jquery-shim.js";
55
import "./dist/ThemePropertiesProvider.js";
66

7+
import "@ui5/webcomponents/dist/MessageBundleAssets.js";
8+
79
import Gregorian from "@ui5/webcomponents-core/dist/sap/ui/core/date/Gregorian.js";
810
import Buddhist from "@ui5/webcomponents-core/dist/sap/ui/core/date/Buddhist.js";
911
import Islamic from "@ui5/webcomponents-core/dist/sap/ui/core/date/Islamic.js";

packages/main/src/ResourceBundleProvider.js renamed to packages/main/src/MessageBundleAssets.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fetchResourceBundle, registerMessageBundles, getResourceBundle } from "@ui5/webcomponents-base/src/ResourceBundle.js";
1+
import { registerMessageBundles } from "@ui5/webcomponents-base/src/ResourceBundle.js";
22

33
import ar from "./i18n/messagebundle_ar.json";
44
import bg from "./i18n/messagebundle_bg.json";
@@ -97,5 +97,3 @@ Suggested pattern: "i18n\\\/.*\\\.json"`);
9797
/* eslint-enable */
9898

9999
registerMessageBundles("@ui5/webcomponents", bundleMap);
100-
101-
export { fetchResourceBundle, getResourceBundle };

packages/main/src/Panel.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import { getIconURI } from "@ui5/webcomponents-base/src/IconPool.js";
44
import slideDown from "@ui5/webcomponents-base/src/animations/slideDown.js";
55
import slideUp from "@ui5/webcomponents-base/src/animations/slideUp.js";
66
import { isSpace, isEnter } from "@ui5/webcomponents-base/src/events/PseudoEvents.js";
7+
import { fetchResourceBundle, getResourceBundle } from "@ui5/webcomponents-base/src/ResourceBundle.js";
78
import Icon from "./Icon.js";
89
import PanelAccessibleRole from "./types/PanelAccessibleRole.js";
910
import PanelRenderer from "./build/compiled/PanelRenderer.lit.js";
10-
import { fetchResourceBundle, getResourceBundle } from "./ResourceBundleProvider.js";
11+
12+
import { PANEL_ICON } from "./i18n/defaults.js";
1113

1214
// Styles
1315
import panelCss from "./themes/Panel.css.js";
@@ -193,14 +195,13 @@ class Panel extends UI5Element {
193195
constructor() {
194196
super();
195197

196-
this.resourceBundle = getResourceBundle("@ui5/webcomponents");
197-
198198
this._header = {};
199199

200200
this._icon = {};
201201
this._icon.id = `${this.id}-CollapsedImg`;
202202
this._icon.src = getIconURI("navigation-right-arrow");
203-
this._icon.title = this.resourceBundle.getText("PANEL_ICON");
203+
this._icon.functional = true;
204+
this.resourceBundle = getResourceBundle("@ui5/webcomponents");
204205

205206
this._toggle = event => { event.preventDefault(); this._toggleOpen(); };
206207
this._noOp = () => {};
@@ -213,6 +214,7 @@ class Panel extends UI5Element {
213214
}
214215

215216
const toggleWithInternalHeader = !this.header;
217+
this._icon.title = this.resourceBundle.getText(PANEL_ICON);
216218
this._header.press = toggleWithInternalHeader ? this._toggle : this._noOp;
217219
this._icon.press = !toggleWithInternalHeader ? this._toggle : this._noOp;
218220
}

packages/main/src/TextArea.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import Bootstrap from "@ui5/webcomponents-base/src/Bootstrap.js";
22
import UI5Element from "@ui5/webcomponents-base/src/UI5Element.js";
33
import CSSSize from "@ui5/webcomponents-base/src/types/CSSSize.js";
44
import Integer from "@ui5/webcomponents-base/src/types/Integer.js";
5+
import { fetchResourceBundle, getResourceBundle } from "@ui5/webcomponents-base/src/ResourceBundle.js";
56
import TextAreaRenderer from "./build/compiled/TextAreaRenderer.lit.js";
6-
import { fetchResourceBundle, getResourceBundle } from "./ResourceBundleProvider.js";
7+
8+
import { TEXTAREA_CHARACTERS_LEFT, TEXTAREA_CHARACTERS_EXCEEDED } from "./i18n/defaults.js";
79

810
// Styles
911
import styles from "./themes/TextArea.css.js";
@@ -231,11 +233,11 @@ class TextArea extends UI5Element {
231233
constructor() {
232234
super();
233235

236+
this.resourceBundle = getResourceBundle("@ui5/webcomponents");
237+
234238
this._listeners = {
235239
change: this._handleChange.bind(this),
236240
};
237-
238-
this.resourceBundle = getResourceBundle("@ui5/webcomponents");
239241
}
240242

241243
onBeforeRendering() {
@@ -319,9 +321,9 @@ class TextArea extends UI5Element {
319321
leftCharactersCount = maxLength - this.value.length;
320322

321323
if (leftCharactersCount >= 0) {
322-
exceededText = this.resourceBundle.getText("TEXTAREA_CHARACTERS_LEFT", [leftCharactersCount]);
324+
exceededText = this.resourceBundle.getText(TEXTAREA_CHARACTERS_LEFT, [leftCharactersCount]);
323325
} else {
324-
exceededText = this.resourceBundle.getText("TEXTAREA_CHARACTERS_EXCEEDED", [Math.abs(leftCharactersCount)]);
326+
exceededText = this.resourceBundle.getText(TEXTAREA_CHARACTERS_EXCEEDED, [Math.abs(leftCharactersCount)]);
325327
}
326328
}
327329
} else {

packages/main/src/Tokenizer.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import Bootstrap from "@ui5/webcomponents-base/src/Bootstrap.js";
22
import UI5Element from "@ui5/webcomponents-base/src/UI5Element.js";
33
import ResizeHandler from "@ui5/webcomponents-base/src/delegate/ResizeHandler.js";
44
import ItemNavigation from "@ui5/webcomponents-base/src/delegate/ItemNavigation.js";
5+
import { fetchResourceBundle, getResourceBundle } from "@ui5/webcomponents-base/src/ResourceBundle.js";
56

6-
import { fetchResourceBundle, getResourceBundle } from "./ResourceBundleProvider.js";
77
import TokenizerRenderer from "./build/compiled/TokenizerRenderer.lit.js";
8+
import { MULTIINPUT_SHOW_MORE_TOKENS } from "./i18n/defaults.js";
89

910
// Styles
1011
import styles from "./themes/Tokenizer.css.js";
1112

13+
1214
// all themes should work via the convenience import (inlined now, switch to json when elements can be imported individyally)
1315
import "./ThemePropertiesProvider.js";
1416

@@ -93,8 +95,9 @@ class Tokenizer extends UI5Element {
9395
return this._getTokens();
9496
};
9597

96-
this._delegates.push(this._itemNav);
9798
this.resourceBundle = getResourceBundle("@ui5/webcomponents");
99+
100+
this._delegates.push(this._itemNav);
98101
}
99102

100103
onBeforeRendering() {
@@ -105,7 +108,7 @@ class Tokenizer extends UI5Element {
105108
}
106109

107110
this._lastTokenCount = this.tokens.length;
108-
this._nMoreText = this.resourceBundle.getText("MULTIINPUT_SHOW_MORE_TOKENS", [this._hiddenTokens.length]);
111+
this._nMoreText = this.resourceBundle.getText(MULTIINPUT_SHOW_MORE_TOKENS, [this._hiddenTokens.length]);
109112
}
110113

111114
onAfterRendering() {
@@ -211,6 +214,7 @@ class Tokenizer extends UI5Element {
211214

212215
static async define(...params) {
213216
await fetchResourceBundle("@ui5/webcomponents");
217+
214218
super.define(...params);
215219
}
216220
}

packages/main/src/i18n/defaults.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const MULTIINPUT_SHOW_MORE_TOKENS = {
2+
key: "MULTIINPUT_SHOW_MORE_TOKENS",
3+
defaultText: "{0} More",
4+
};
5+
6+
const TEXTAREA_CHARACTERS_LEFT = {
7+
key: "TEXTAREA_CHARACTERS_LEFT",
8+
defaultText: "{0} characters remaining",
9+
};
10+
11+
const TEXTAREA_CHARACTERS_EXCEEDED = {
12+
key: "TEXTAREA_CHARACTERS_EXCEEDED",
13+
defaultText: "{0} characters over limit",
14+
};
15+
16+
const PANEL_ICON = {
17+
key: "PANEL_ICON",
18+
defaultText: "Expand/Collapse",
19+
};
20+
21+
export {
22+
MULTIINPUT_SHOW_MORE_TOKENS,
23+
TEXTAREA_CHARACTERS_LEFT,
24+
TEXTAREA_CHARACTERS_EXCEEDED,
25+
PANEL_ICON,
26+
};

packages/main/test/sap/ui/webcomponents/main/qunit/Panel.qunit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ TestHelper.ready(function () {
3232
QUnit.test("The default 'headerText' is empty string", function (assert) {
3333
var panel = this.getPanelRoot(),
3434
sExpected = "";
35-
35+
3636
assert.equal(panel.querySelector(".sapMPanelHdr").innerText.trim(), sExpected, "headerText is empty string");
3737
});
3838

0 commit comments

Comments
 (0)