@applicaster/zapp-react-dom-app 12.0.0-rc.7 → 12.0.0-rc.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/App/InteractionManager/index.tsx +9 -0
- package/App/Loader/appLoader.js +2 -6
- package/App/Loader/setUpRTL.js +3 -3
- package/App/Loader/utils/__tests__/getLanguageCode.test.js +0 -1
- package/App/Loader/utils/index.js +19 -18
- package/Polyfills/AnalyticsBridge/index.ts +5 -1
- package/Polyfills/AppLoaderBridge/utils/enums.ts +1 -0
- package/Polyfills/QuickBrickCommunicationModule/__tests__/index.test.js +225 -0
- package/Polyfills/QuickBrickCommunicationModule/index.js +115 -52
- package/package.json +6 -6
- package/App/Loader/utils/__tests__/getAvailableAppLanguages.test.js +0 -35
|
@@ -592,6 +592,12 @@ export function withInteractionManager(Component: React.FC) {
|
|
|
592
592
|
focusManager.moveFocus(direction);
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
+
if (!isDialogVisible) {
|
|
596
|
+
// run focus recovery on user interaction attempt
|
|
597
|
+
// probably we failed to set initial focus for some reason
|
|
598
|
+
focusManager.recoverFocus();
|
|
599
|
+
}
|
|
600
|
+
|
|
595
601
|
if (
|
|
596
602
|
displayState === DISPLAY_STATES.PLAYER ||
|
|
597
603
|
displayState === DISPLAY_STATES.HUD
|
|
@@ -656,6 +662,9 @@ export function withInteractionManager(Component: React.FC) {
|
|
|
656
662
|
|
|
657
663
|
onConfirmDialogClose() {
|
|
658
664
|
this.confirmDialog.hideDialog();
|
|
665
|
+
|
|
666
|
+
// restore initial focus after closing dialog
|
|
667
|
+
focusManager.setInitialFocus();
|
|
659
668
|
}
|
|
660
669
|
|
|
661
670
|
render() {
|
package/App/Loader/appLoader.js
CHANGED
|
@@ -8,11 +8,7 @@ export const appLoaderImpl =
|
|
|
8
8
|
) =>
|
|
9
9
|
async (dispatch, getState) => {
|
|
10
10
|
try {
|
|
11
|
-
const {
|
|
12
|
-
plugins,
|
|
13
|
-
pluginConfigurations,
|
|
14
|
-
remoteConfigurations: { localizations },
|
|
15
|
-
} = getState();
|
|
11
|
+
const { plugins, pluginConfigurations } = getState();
|
|
16
12
|
|
|
17
13
|
// Await crucial tasks
|
|
18
14
|
await loadLocale();
|
|
@@ -20,7 +16,7 @@ export const appLoaderImpl =
|
|
|
20
16
|
await loadAnalyticsPlugins(plugins, pluginConfigurations);
|
|
21
17
|
|
|
22
18
|
// Remaining loaders
|
|
23
|
-
const loaders = [loadDomPlugins(plugins), setUpRTL(
|
|
19
|
+
const loaders = [loadDomPlugins(plugins), setUpRTL()];
|
|
24
20
|
|
|
25
21
|
// Await for the remaining tasks and return when they are all complete
|
|
26
22
|
await Promise.all(loaders);
|
package/App/Loader/setUpRTL.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
2
2
|
import { I18nManager } from "react-native";
|
|
3
3
|
|
|
4
|
-
export async function setUpRTL(
|
|
5
|
-
const isRTL =
|
|
4
|
+
export async function setUpRTL() {
|
|
5
|
+
const isRTL = getIsRTL();
|
|
6
6
|
I18nManager.forceRTL(isRTL);
|
|
7
7
|
}
|
|
@@ -8,7 +8,7 @@ export const getLanguageCodeFromLocalStorage = () => {
|
|
|
8
8
|
return NativeModules.LocalStorage.getItem(UI_LANGUAGE);
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
export const
|
|
11
|
+
export const persistLanguageSelection = async (languageCode) => {
|
|
12
12
|
await NativeModules.SessionStorage.setItem(UI_LANGUAGE, languageCode);
|
|
13
13
|
|
|
14
14
|
return NativeModules.LocalStorage.setItem(UI_LANGUAGE, languageCode);
|
|
@@ -61,32 +61,34 @@ export const getLanguageCodeImpl =
|
|
|
61
61
|
(
|
|
62
62
|
GetLanguageCodeFromLocalStorage,
|
|
63
63
|
GetAvailableAppLanguages,
|
|
64
|
-
PickBestMatchedLanguage
|
|
65
|
-
SetLanguageCodeToLocalStorage
|
|
64
|
+
PickBestMatchedLanguage
|
|
66
65
|
) =>
|
|
67
66
|
async (locale) => {
|
|
68
67
|
const languageFromLocalStorage = await GetLanguageCodeFromLocalStorage();
|
|
69
68
|
|
|
70
69
|
if (languageFromLocalStorage) {
|
|
71
70
|
return languageFromLocalStorage;
|
|
72
|
-
}
|
|
73
|
-
const availableAppLanguages = GetAvailableAppLanguages();
|
|
71
|
+
}
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
locale,
|
|
77
|
-
availableAppLanguages
|
|
78
|
-
);
|
|
73
|
+
const availableAppLanguages = GetAvailableAppLanguages();
|
|
79
74
|
|
|
80
|
-
|
|
75
|
+
const pickedLanguage = PickBestMatchedLanguage(
|
|
76
|
+
locale,
|
|
77
|
+
availableAppLanguages
|
|
78
|
+
);
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
}
|
|
80
|
+
return pickedLanguage;
|
|
84
81
|
};
|
|
85
82
|
|
|
86
83
|
/**
|
|
87
|
-
|
|
88
|
-
*
|
|
89
|
-
*
|
|
84
|
+
/**
|
|
85
|
+
* Loads and sets locale-related information in the QuickBrickCommunicationModule.
|
|
86
|
+
* This function adds uiLanguage, countryLocale, languageLocale, and languageCode to the module.
|
|
87
|
+
*
|
|
88
|
+
* @param {Function} GetLocale - Function to retrieve the current locale.
|
|
89
|
+
* @param {Function} GetLanguageCode - Function to determine the language code based on available languages.
|
|
90
|
+
* @param {Object} quickBrickCommunicationModule - The module to be updated with locale information.
|
|
91
|
+
* @returns {Promise<Function>} An async function that loads and sets the locale information.
|
|
90
92
|
* Warning! This function mutates QuickBrickCommunicationModule
|
|
91
93
|
*/
|
|
92
94
|
export const loadLocaleImpl =
|
|
@@ -101,14 +103,13 @@ export const loadLocaleImpl =
|
|
|
101
103
|
quickBrickCommunicationModule.countryLocale = R.toUpper(countryLocale);
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
// setup languageCode
|
|
105
106
|
const languageCode = await GetLanguageCode(locale);
|
|
106
107
|
quickBrickCommunicationModule.languageCode = languageCode;
|
|
108
|
+
quickBrickCommunicationModule.uiLanguage = languageCode;
|
|
107
109
|
};
|
|
108
110
|
|
|
109
111
|
export const getLanguageCode = getLanguageCodeImpl(
|
|
110
112
|
getLanguageCodeFromLocalStorage,
|
|
111
113
|
getAvailableAppLanguages,
|
|
112
|
-
pickBestMatchedLanguage
|
|
113
|
-
setLanguageCodeToLocalStorage
|
|
114
|
+
pickBestMatchedLanguage
|
|
114
115
|
);
|
|
@@ -105,7 +105,11 @@ function isInvalidAnalyticsData(eventName, payload = null) {
|
|
|
105
105
|
|
|
106
106
|
export const AnalyticsBridge = (function () {
|
|
107
107
|
let registeredAnalyticPlugins: {
|
|
108
|
-
module: {
|
|
108
|
+
module: {
|
|
109
|
+
sendEvent: Function;
|
|
110
|
+
initialize?: Function;
|
|
111
|
+
getPlayerConfiguration?: Function;
|
|
112
|
+
};
|
|
109
113
|
configuration?: any;
|
|
110
114
|
}[] = [];
|
|
111
115
|
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
const mockPersistLanguageSelection = jest.fn();
|
|
2
|
+
|
|
3
|
+
jest.mock("../../../App/Loader/utils", () => ({
|
|
4
|
+
persistLanguageSelection: mockPersistLanguageSelection,
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
const mockGetAppData = jest.fn();
|
|
8
|
+
|
|
9
|
+
jest.mock("../../AppData", () => ({
|
|
10
|
+
getAppData: mockGetAppData,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock("@applicaster/zapp-react-native-bridge/QuickBrick", () => ({
|
|
14
|
+
QUICK_BRICK_EVENTS: {
|
|
15
|
+
QUICK_BRICK_READY: "QUICK_BRICK_READY",
|
|
16
|
+
FORCE_APP_RELOAD: "FORCE_APP_RELOAD",
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
const mocked_storage = {
|
|
21
|
+
"applicaster.v2_::_uiLanguage": "en-UK",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
global.window.location = {
|
|
25
|
+
reload: jest.fn(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
global.window.localStorage = {
|
|
29
|
+
getItem: jest.fn((key) => mocked_storage[key] || null),
|
|
30
|
+
setItem: jest.fn((key, value) => {
|
|
31
|
+
mocked_storage[key] = value;
|
|
32
|
+
}),
|
|
33
|
+
removeItem: jest.fn((key) => {
|
|
34
|
+
delete mocked_storage[key];
|
|
35
|
+
}),
|
|
36
|
+
clear: jest.fn(),
|
|
37
|
+
length: 1,
|
|
38
|
+
key: jest.fn(),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const BASE_MOCK_APP_DATA = {
|
|
42
|
+
accountsAccountId: "abcid123",
|
|
43
|
+
appFamilyId: 1710,
|
|
44
|
+
appName: "App.TV",
|
|
45
|
+
buildVersion: 247,
|
|
46
|
+
bundleIdentifier: "com.bundleIdentifier",
|
|
47
|
+
deviceTarget: "samsung_tv",
|
|
48
|
+
languages: ["en", "en-US", "fr", "fr-FR"],
|
|
49
|
+
locale: "en",
|
|
50
|
+
quickBrickVersion: "11.1.13",
|
|
51
|
+
quickBrickEvent: () => {},
|
|
52
|
+
setAppLanguage: () => {},
|
|
53
|
+
initialProps: {},
|
|
54
|
+
riversConfigurationId: "riverid123",
|
|
55
|
+
sdkVersion: "1.0.0",
|
|
56
|
+
store: "samsung",
|
|
57
|
+
urlSchemePrefix: "app-tv",
|
|
58
|
+
versionId: "version1233",
|
|
59
|
+
versionName: "1.0.8",
|
|
60
|
+
bver: "1.0.8",
|
|
61
|
+
os_type: "web",
|
|
62
|
+
platform: "samsung_tv",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const getMockAppData = (overrides = {}) => ({
|
|
66
|
+
...BASE_MOCK_APP_DATA,
|
|
67
|
+
...overrides,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("QuickBrickCommunicationModule Polyfill", () => {
|
|
71
|
+
let originalWindow;
|
|
72
|
+
let QuickBrickModule;
|
|
73
|
+
let mockAppData;
|
|
74
|
+
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
jest.resetModules();
|
|
77
|
+
originalWindow = global.window;
|
|
78
|
+
|
|
79
|
+
// Get fresh mockAppData for each test
|
|
80
|
+
mockAppData = getMockAppData();
|
|
81
|
+
mockGetAppData.mockReturnValue(mockAppData);
|
|
82
|
+
|
|
83
|
+
window.localStorage.getItem.mockClear();
|
|
84
|
+
window.localStorage.setItem.mockClear();
|
|
85
|
+
window.localStorage.removeItem.mockClear();
|
|
86
|
+
window.localStorage.clear.mockClear();
|
|
87
|
+
|
|
88
|
+
QuickBrickModule = require("../index");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
afterEach(() => {
|
|
92
|
+
global.window = originalWindow;
|
|
93
|
+
jest.clearAllMocks();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("getMatchingLanguageFromBuildData", () => {
|
|
97
|
+
it("should return default locale (en) if there are no languages listed in build time parameters", () => {
|
|
98
|
+
window.localStorage.getItem.mockReturnValue(undefined);
|
|
99
|
+
global.window.navigator.language = "ru-RU";
|
|
100
|
+
mockGetAppData.mockReturnValue(getMockAppData({ languages: null }));
|
|
101
|
+
|
|
102
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
103
|
+
|
|
104
|
+
expect(result).toEqual({
|
|
105
|
+
uiLanguage: "en",
|
|
106
|
+
languageCode: "en",
|
|
107
|
+
countryLocale: "",
|
|
108
|
+
languageLocale: "en",
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should fallback to default language if browser / device locale (en-UK) does not match list of supported languages", () => {
|
|
113
|
+
// localizations: ["en", "en-US", "fr", "fr-FR"], device_language: en, device_region: UK -> ui: en, language: en, region: UK
|
|
114
|
+
|
|
115
|
+
global.window.navigator.language = "en-UK";
|
|
116
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
117
|
+
|
|
118
|
+
expect(result).toEqual({
|
|
119
|
+
uiLanguage: "en",
|
|
120
|
+
languageCode: "en",
|
|
121
|
+
countryLocale: "",
|
|
122
|
+
languageLocale: "en",
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should use browser / device locale (en-US) when it matches one of the supported languages", () => {
|
|
127
|
+
// localizations: ["en", "en-US", "fr", "fr-FR"], device_language: en, device_region: US -> ui: en-US, language: en, region: US
|
|
128
|
+
|
|
129
|
+
global.window.navigator.language = "en-US";
|
|
130
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
131
|
+
|
|
132
|
+
expect(result).toEqual({
|
|
133
|
+
uiLanguage: "en-US",
|
|
134
|
+
languageCode: "en",
|
|
135
|
+
countryLocale: "US",
|
|
136
|
+
languageLocale: "en-US",
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should fallback to default language if browser / device locale (ru-RU) does not match list of supported languages", () => {
|
|
141
|
+
// localizations: ["en", "en-US", "fr", "fr-FR"], device_language: ru, device_region: RU -> ui: en, language: en, region: ""
|
|
142
|
+
global.window.navigator.language = "ru-RU";
|
|
143
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
144
|
+
|
|
145
|
+
expect(result).toEqual({
|
|
146
|
+
uiLanguage: "en",
|
|
147
|
+
languageCode: "en",
|
|
148
|
+
countryLocale: "",
|
|
149
|
+
languageLocale: "en",
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should use browser / device locale (fr-FR) when it matches one of the supported language", () => {
|
|
154
|
+
// localizations: ["en", "en-US", "fr", "fr-FR"], device_language: fr, device_region: FR -> ui: fr, language: fr, region: FR
|
|
155
|
+
global.window.navigator.language = "fr-FR";
|
|
156
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
157
|
+
|
|
158
|
+
expect(result).toEqual({
|
|
159
|
+
uiLanguage: "fr-FR",
|
|
160
|
+
languageCode: "fr",
|
|
161
|
+
countryLocale: "FR",
|
|
162
|
+
languageLocale: "fr-FR",
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should use user-selected language (en-US) if it was persisted in local storage", () => {
|
|
167
|
+
window.localStorage.getItem.mockReturnValue("en-US");
|
|
168
|
+
|
|
169
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
170
|
+
|
|
171
|
+
expect(window.localStorage.getItem).toHaveBeenCalled();
|
|
172
|
+
|
|
173
|
+
expect(result).toEqual({
|
|
174
|
+
uiLanguage: "en-US",
|
|
175
|
+
languageCode: "en",
|
|
176
|
+
countryLocale: "US",
|
|
177
|
+
languageLocale: "en-US",
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should use locale (fr-FR) from browser / device if no user selection is found in storage", () => {
|
|
182
|
+
window.localStorage.getItem.mockReturnValue(undefined);
|
|
183
|
+
global.window.navigator.language = "fr-FR";
|
|
184
|
+
const result = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
185
|
+
|
|
186
|
+
expect(result).toEqual({
|
|
187
|
+
uiLanguage: "fr-FR",
|
|
188
|
+
languageCode: "fr",
|
|
189
|
+
countryLocale: "FR",
|
|
190
|
+
languageLocale: "fr-FR",
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe("setAppLanguage", () => {
|
|
196
|
+
it("should persist language selection and reload the page", async () => {
|
|
197
|
+
await QuickBrickModule.setAppLanguage("fr-FR");
|
|
198
|
+
|
|
199
|
+
expect(mockPersistLanguageSelection).toHaveBeenCalledWith("fr-FR");
|
|
200
|
+
expect(window.location.reload).toHaveBeenCalled();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe("QuickBrickCommunicationModule", () => {
|
|
205
|
+
it("should initialize with the required app data", () => {
|
|
206
|
+
expect(QuickBrickModule.QuickBrickCommunicationModule).toMatchObject({
|
|
207
|
+
...mockAppData,
|
|
208
|
+
platform: mockAppData.deviceTarget,
|
|
209
|
+
setAppLanguage: expect.any(Function),
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("should include locale data after calling getMatchingLanguageBuildData", () => {
|
|
214
|
+
const localeData = QuickBrickModule.getMatchingLanguageFromBuildData();
|
|
215
|
+
const result = { ...mockAppData, ...localeData };
|
|
216
|
+
|
|
217
|
+
Object.entries(result).forEach(([key, value]) => {
|
|
218
|
+
expect(QuickBrickModule.QuickBrickCommunicationModule).toHaveProperty(
|
|
219
|
+
key,
|
|
220
|
+
typeof value === "function" ? expect.any(Function) : value
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import { persistLanguageSelection } from "../../App/Loader/utils";
|
|
4
|
+
|
|
5
|
+
import { getAppData } from "../AppData";
|
|
5
6
|
import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
7
|
+
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
8
|
+
|
|
9
|
+
const { log_error, log_debug, log_warning } = createLogger({
|
|
10
|
+
category: "QuickBrickCommunicationModule",
|
|
11
|
+
subsystem: "zapp-react-dom-app",
|
|
12
|
+
});
|
|
6
13
|
|
|
7
14
|
const QuickBrickEventEmitter = {};
|
|
8
15
|
|
|
@@ -63,98 +70,154 @@ try {
|
|
|
63
70
|
console.warn("cannot assign QuickBrickEvents to window", e.message);
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
function quickBrickEvent(eventName, payload) {
|
|
73
|
+
export function quickBrickEvent(eventName, payload) {
|
|
67
74
|
QuickBrickEventEmitter.sendEvent(eventName, payload);
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
const initialProps = {}; // required for legacy plugins;
|
|
71
78
|
|
|
72
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Retrieves the browser locale, which represents the device locale for SmartTVs.
|
|
81
|
+
*
|
|
82
|
+
* @returns {string|undefined} The browser locale string (e.g., "en-US") or undefined if an error occurs.
|
|
83
|
+
*
|
|
84
|
+
* TODO: We can later get more accurate locale data with device APIs, if needed
|
|
85
|
+
*/
|
|
86
|
+
export function getBrowserLocale() {
|
|
73
87
|
try {
|
|
74
88
|
return window.navigator.language;
|
|
75
89
|
} catch (e) {
|
|
76
|
-
|
|
77
|
-
console.error("Could not determine browser locale", e);
|
|
90
|
+
log_error("Could not determine locale", e);
|
|
78
91
|
}
|
|
79
92
|
}
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Updates the UI language, persists the selection, and reloads the application.
|
|
96
|
+
* This method is used by the QuickBrick Language Selector to change the app's language.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} uiLanguage - en-UK, en-US, etc.
|
|
99
|
+
* @returns {Promise<void>}
|
|
100
|
+
*
|
|
101
|
+
* Usage: plugins/quick-brick-language-selector/src/utils/index.ts
|
|
102
|
+
*/
|
|
103
|
+
export const setAppLanguage = async (uiLanguage) => {
|
|
104
|
+
await persistLanguageSelection(uiLanguage);
|
|
90
105
|
|
|
91
|
-
// reload web page
|
|
92
106
|
window.location.reload();
|
|
93
107
|
};
|
|
94
108
|
|
|
95
|
-
const buildTimeData =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
109
|
+
const buildTimeData = getAppData();
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* This method retrieves the all of the language data we need from the build data, and the browser locale.
|
|
113
|
+
* @returns localeData
|
|
114
|
+
* @returns localeData.uiLanguage - The language code to use for the app.
|
|
115
|
+
* @returns localeData.countryLocale - The country locale code.
|
|
116
|
+
* @returns localeData.languageLocale - The language locale code.
|
|
117
|
+
* @returns localeData.languageCode - The language code.
|
|
118
|
+
*/
|
|
119
|
+
export const getMatchingLanguageFromBuildData = () => {
|
|
120
|
+
// Locale is a build time value we get from Zapp, so we can use it as a fallback
|
|
99
121
|
const { locale, languages } = buildTimeData || {};
|
|
122
|
+
const browserLocale = getBrowserLocale();
|
|
123
|
+
|
|
124
|
+
if (!Array.isArray(languages)) {
|
|
125
|
+
log_error("Missing required 'languages' from the build time data.", {
|
|
126
|
+
buildTimeData,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
uiLanguage: locale,
|
|
131
|
+
languageCode: locale,
|
|
132
|
+
countryLocale: "",
|
|
133
|
+
languageLocale: locale,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
100
136
|
|
|
101
|
-
// TODO: refactor: tryAndResolve used in Storage is promise
|
|
102
137
|
const userSelectedLanguage = window.localStorage.getItem(
|
|
103
138
|
"applicaster.v2_::_uiLanguage"
|
|
104
139
|
);
|
|
105
140
|
|
|
106
|
-
if (!locale && !Array.isArray(languages)) {
|
|
107
|
-
// eslint-disable-next-line no-console
|
|
108
|
-
console.error("Missing required 'locale' and 'language' build time data.");
|
|
109
|
-
|
|
110
|
-
// Default language
|
|
111
|
-
return locale;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
141
|
if (userSelectedLanguage) {
|
|
115
|
-
if (languages.
|
|
116
|
-
|
|
142
|
+
if (languages.find((lang) => lang === userSelectedLanguage)) {
|
|
143
|
+
const [languageCode, countryLocale] = userSelectedLanguage.split("-");
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
uiLanguage: userSelectedLanguage,
|
|
147
|
+
languageCode,
|
|
148
|
+
countryLocale: countryLocale || "",
|
|
149
|
+
languageLocale: userSelectedLanguage,
|
|
150
|
+
};
|
|
117
151
|
}
|
|
118
152
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
log_debug(
|
|
154
|
+
"User selected language is not present in available localizations, selecting language using browser or device locale",
|
|
155
|
+
|
|
156
|
+
{ userSelectedLanguage, languages }
|
|
122
157
|
);
|
|
123
158
|
}
|
|
124
159
|
|
|
125
160
|
if (!browserLocale) {
|
|
126
|
-
|
|
127
|
-
|
|
161
|
+
log_warning(
|
|
162
|
+
"Could not use browser or device locale to determine language, falling back to default locale",
|
|
163
|
+
{ browserLocale, locale }
|
|
164
|
+
);
|
|
128
165
|
|
|
129
|
-
return
|
|
166
|
+
return {
|
|
167
|
+
uiLanguage: locale,
|
|
168
|
+
languageCode: locale,
|
|
169
|
+
countryLocale: "",
|
|
170
|
+
languageLocale: locale,
|
|
171
|
+
};
|
|
130
172
|
}
|
|
131
173
|
|
|
132
|
-
//
|
|
133
|
-
const
|
|
174
|
+
// Exact match
|
|
175
|
+
const [browserLanguageCode, browserCountryLocale] = browserLocale.split("-");
|
|
176
|
+
const browserLocaleMatch = languages.find((lang) => lang === browserLocale);
|
|
134
177
|
|
|
135
|
-
if (
|
|
136
|
-
return
|
|
178
|
+
if (browserLocaleMatch) {
|
|
179
|
+
return {
|
|
180
|
+
uiLanguage: browserLocaleMatch,
|
|
181
|
+
languageCode: browserLanguageCode,
|
|
182
|
+
countryLocale: browserCountryLocale || "",
|
|
183
|
+
languageLocale: browserLocaleMatch,
|
|
184
|
+
};
|
|
137
185
|
}
|
|
138
186
|
|
|
139
|
-
//
|
|
140
|
-
|
|
187
|
+
// If there is no user-selected language, or the user-selected language is not found in the list of supported languages,
|
|
188
|
+
// and the browser locale is also not found in the list of supported languages,
|
|
189
|
+
// then fallback to the default language from the list of supported languages, while preserving the country locale from the browser.
|
|
190
|
+
const defaultLanguage = languages[0];
|
|
141
191
|
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
}
|
|
192
|
+
if (defaultLanguage) {
|
|
193
|
+
const [languageCode, countryLocale] = defaultLanguage.split("-");
|
|
145
194
|
|
|
146
|
-
|
|
147
|
-
|
|
195
|
+
const defaultLocale = {
|
|
196
|
+
uiLanguage: defaultLanguage,
|
|
197
|
+
languageCode,
|
|
198
|
+
countryLocale: countryLocale || "",
|
|
199
|
+
languageLocale: defaultLanguage,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
log_debug(
|
|
203
|
+
"Locale not found in the list of supported languages, falling back to the default language locale",
|
|
204
|
+
{ defaultLocale, browserLocale, languages }
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
return defaultLocale;
|
|
208
|
+
}
|
|
148
209
|
};
|
|
149
210
|
|
|
211
|
+
const localeData = getMatchingLanguageFromBuildData();
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* QuickBrickCommunicationModule object is a Polyfill that mimicks how we interface with the Native platforms
|
|
215
|
+
*/
|
|
150
216
|
export const QuickBrickCommunicationModule = {
|
|
151
217
|
quickBrickEvent,
|
|
152
218
|
initialProps,
|
|
153
219
|
...buildTimeData,
|
|
220
|
+
...localeData,
|
|
154
221
|
platform: buildTimeData.deviceTarget,
|
|
155
|
-
languageLocale: languageCode,
|
|
156
|
-
countryLocale,
|
|
157
222
|
setAppLanguage,
|
|
158
|
-
countryCode: countryLocale,
|
|
159
|
-
uiLanguage: getMatchingLanguageFromBuildData(),
|
|
160
223
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-dom-app",
|
|
3
|
-
"version": "12.0.0-rc.
|
|
3
|
+
"version": "12.0.0-rc.71",
|
|
4
4
|
"description": "Zapp App Component for Applicaster's Quick Brick React Native App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@applicaster/zapp-react-dom-ui-components": "12.0.0-rc.
|
|
26
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-rc.
|
|
27
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-rc.
|
|
28
|
-
"@applicaster/zapp-react-native-ui-components": "12.0.0-rc.
|
|
29
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-rc.
|
|
25
|
+
"@applicaster/zapp-react-dom-ui-components": "12.0.0-rc.71",
|
|
26
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-rc.71",
|
|
27
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-rc.71",
|
|
28
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-rc.71",
|
|
29
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-rc.71",
|
|
30
30
|
"abortcontroller-polyfill": "^1.7.5",
|
|
31
31
|
"history": "^4.7.2",
|
|
32
32
|
"react-router-dom": "^5.1.2",
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { getAvailableAppLanguagesImpl as getAvailableAppLanguages } from "..";
|
|
2
|
-
|
|
3
|
-
describe("getAvailableAppLanguages", () => {
|
|
4
|
-
it("return list of languages", () => {
|
|
5
|
-
// setup
|
|
6
|
-
const appStore = {
|
|
7
|
-
get: () => ({
|
|
8
|
-
localizations: {
|
|
9
|
-
en: "en_value",
|
|
10
|
-
de: "de_value",
|
|
11
|
-
fr: "fr_value",
|
|
12
|
-
"en-UK": "en-UK_value",
|
|
13
|
-
"en-GB": "en-GB_value",
|
|
14
|
-
},
|
|
15
|
-
}),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// verify
|
|
19
|
-
expect(getAvailableAppLanguages(appStore)).toEqual([
|
|
20
|
-
"en",
|
|
21
|
-
"de",
|
|
22
|
-
"fr",
|
|
23
|
-
"en-UK",
|
|
24
|
-
"en-GB",
|
|
25
|
-
]);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("return list of languages", () => {
|
|
29
|
-
// setup
|
|
30
|
-
const appStore = undefined;
|
|
31
|
-
|
|
32
|
-
// verify
|
|
33
|
-
expect(getAvailableAppLanguages(appStore)).toEqual([]);
|
|
34
|
-
});
|
|
35
|
-
});
|