Skip to content

Commit e4d18a9

Browse files
authored
improve defaultLocale behaviour post compilation
1 parent c2b6fb2 commit e4d18a9

File tree

12 files changed

+633
-397
lines changed

12 files changed

+633
-397
lines changed

bootstrap/src/component/Globalisation.jsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
/* global DEFAULT_LOCALE */
2-
31
import { useMemo, Fragment } from "react";
42
import { createIntl, createIntlCache, RawIntlProvider } from "react-intl";
53
import { useSelector } from "react-redux";
64

7-
import { getLanguage, getI18nMessages } from "../selector";
5+
import { getLanguage, getI18nMessagesFacade } from "../selector";
86

97
const cache = createIntlCache();
108

119
const Globalisation = (props) => {
10+
const getI18nMessages = useMemo(() => getI18nMessagesFacade(props.defaultLocale), [props.defaultLocale]);
11+
1212
const locale = useSelector(getLanguage);
1313
const messages = useSelector(getI18nMessages);
1414

@@ -17,7 +17,7 @@ const Globalisation = (props) => {
1717
createIntl(
1818
{
1919
locale,
20-
defaultLocale: DEFAULT_LOCALE,
20+
defaultLocale: props.defaultLocale,
2121
textComponent: Fragment,
2222
messages,
2323
onError: (err) => {
@@ -28,7 +28,7 @@ const Globalisation = (props) => {
2828
},
2929
cache,
3030
),
31-
[locale, messages],
31+
[props.defaultLocale, locale, messages],
3232
);
3333

3434
return <RawIntlProvider value={intl}>{props.children}</RawIntlProvider>;

bootstrap/src/component/Main.jsx

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/* global DEFAULT_LOCALE */
2-
31
import { Children, StrictMode, useState, useCallback, useEffect } from "react";
42
import { Provider as ReduxProvider, useSelector } from "react-redux";
53

@@ -11,6 +9,8 @@ import setupStore from "../store";
119
import Entrypoint, { router } from "./Entrypoint";
1210
import Globalisation from "./Globalisation";
1311

12+
const DEFAULT_LOCALE = "en-US";
13+
1414
const FullyInitializedGate = (props) => {
1515
const initialized = useSelector(getIsInitialized);
1616
const locale = useSelector(getLanguage);
@@ -31,7 +31,7 @@ const Main = (props) => {
3131
store.dispatch({
3232
type: constants.SET_LANGUAGE,
3333
payload: {
34-
language: DEFAULT_LOCALE,
34+
language: props.defaultLocale ?? DEFAULT_LOCALE,
3535
},
3636
});
3737
store.dispatch({
@@ -46,7 +46,14 @@ const Main = (props) => {
4646
throw error;
4747
});
4848
}
49-
}, [markStoreReady, setErrorState, props.reduxMiddlewares, props.fetchContext, props.contextRefreshInterval]);
49+
}, [
50+
markStoreReady,
51+
setErrorState,
52+
props.defaultLocale,
53+
props.reduxMiddlewares,
54+
props.fetchContext,
55+
props.contextRefreshInterval,
56+
]);
5057

5158
useEffect(() => {
5259
manualCleanup();
@@ -64,7 +71,7 @@ const Main = (props) => {
6471
<StrictMode>
6572
<ReduxProvider store={getStore()}>
6673
<FullyInitializedGate>
67-
<Globalisation>
74+
<Globalisation defaultLocale={props.defaultLocale ?? DEFAULT_LOCALE}>
6875
<Entrypoint />
6976
</Globalisation>
7077
</FullyInitializedGate>

bootstrap/src/component/__tests__/Main.test.jsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ class ErrorBoundary extends React.Component {
7373

7474
describe("<Main />", () => {
7575
beforeEach(() => {
76-
global.DEFAULT_LOCALE = "en-US";
7776
mockStore.clearActions();
7877
});
7978

@@ -95,9 +94,8 @@ describe("<Main />", () => {
9594
});
9695

9796
it("should use provided default locale", async () => {
98-
global.DEFAULT_LOCALE = "fr-FR";
9997
const fetchContext = jest.fn();
100-
render(<Main contextRefreshInterval={10} fetchContext={fetchContext} />);
98+
render(<Main contextRefreshInterval={10} fetchContext={fetchContext} defaultLocale="fr-FR" />);
10199
await waitFor(() => {
102100
expect(screen.getByTestId("module/some-entrypoint")).toBeInTheDocument();
103101
});

bootstrap/src/selector/__test__/index.test.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ describe("selector", () => {
44
let state = null;
55

66
beforeEach(() => {
7-
global.DEFAULT_LOCALE = "en-US";
87
state = {
98
runtime: {
109
entrypoint: "value",
@@ -32,22 +31,26 @@ describe("selector", () => {
3231
});
3332
});
3433

35-
describe(".getI18nMessages", () => {
34+
describe(".getI18nMessagesFacade", () => {
35+
it("should return function", () => {
36+
expect(typeof selectors.getI18nMessagesFacade("en-US")).toEqual("function");
37+
});
38+
3639
it("should return a structure supporting getting i18n keys", () => {
37-
const messages = selectors.getI18nMessages(state);
40+
const messages = selectors.getI18nMessagesFacade("en-US")(state);
3841
expect(messages.foo).toEqual(state.env.messages["en-US"].foo);
3942
expect(messages.miss).toBeUndefined();
4043
});
4144

42-
it("should fallback on DEFAULT_LOCALE when it is missing in current locale", () => {
45+
it("should fallback on default locale when it is missing in current locale", () => {
4346
state.env.language = "fr-FR";
44-
const messages = selectors.getI18nMessages(state);
47+
const messages = selectors.getI18nMessagesFacade("en-US")(state);
4548
expect(messages.foo).toEqual(state.env.messages["en-US"].foo);
4649
});
4750

4851
it("should work properly when no messages exist at all", () => {
4952
delete state.env.messages;
50-
const messages = selectors.getI18nMessages(state);
53+
const messages = selectors.getI18nMessagesFacade("en-US")(state);
5154
expect(messages.foo).toBeUndefined();
5255
});
5356
});

bootstrap/src/selector/index.js

+44-41
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,53 @@
1-
/* global DEFAULT_LOCALE */
2-
31
const emptydict = {};
42

5-
const memoizedMessages = new Proxy(
6-
{
7-
fallback: emptydict,
8-
primary: emptydict,
9-
descriptor: { configurable: true, enumerable: true },
10-
},
11-
{
12-
getOwnPropertyDescriptor(ref, _key) {
13-
return ref.descriptor;
14-
},
15-
get(ref, key) {
16-
if (key in ref.primary) {
17-
return ref.primary[key];
18-
}
19-
if (key in ref.fallback) {
20-
return ref.fallback[key];
21-
}
22-
return undefined;
3+
function createMessagesWithFallback(defaultLocale) {
4+
return new Proxy(
5+
{
6+
fallback: emptydict,
7+
primary: emptydict,
8+
descriptor: { configurable: true, enumerable: true },
239
},
24-
set(ref, locale, messages) {
25-
if (!messages) {
26-
ref.primary = emptydict;
27-
ref.fallback = emptydict;
10+
{
11+
getOwnPropertyDescriptor(ref, _key) {
12+
return ref.descriptor;
13+
},
14+
get(ref, key) {
15+
if (key in ref.primary) {
16+
return ref.primary[key];
17+
}
18+
if (key in ref.fallback) {
19+
return ref.fallback[key];
20+
}
21+
return undefined;
22+
},
23+
set(ref, locale, messages) {
24+
if (!messages) {
25+
ref.primary = emptydict;
26+
ref.fallback = emptydict;
27+
return true;
28+
}
29+
if (locale in messages) {
30+
ref.primary = messages[locale];
31+
} else {
32+
ref.primary = emptydict;
33+
}
34+
if (defaultLocale in messages) {
35+
ref.fallback = messages[defaultLocale];
36+
} else {
37+
ref.fallback = emptydict;
38+
}
2839
return true;
29-
}
30-
if (locale in messages) {
31-
ref.primary = messages[locale];
32-
} else {
33-
ref.primary = emptydict;
34-
}
35-
if (DEFAULT_LOCALE in messages) {
36-
ref.fallback = messages[DEFAULT_LOCALE];
37-
} else {
38-
ref.fallback = emptydict;
39-
}
40-
return true;
40+
},
4141
},
42-
},
43-
);
42+
);
43+
}
4444

45-
export const getI18nMessages = (state) => {
46-
memoizedMessages[state.env.language] = state.env.messages;
47-
return memoizedMessages;
45+
export const getI18nMessagesFacade = (defaultLocale) => {
46+
const memo = createMessagesWithFallback(defaultLocale);
47+
return (state) => {
48+
memo[state.env.language] = state.env.messages;
49+
return memo;
50+
};
4851
};
4952

5053
export const getIsInitialized = (state) => state.runtime.initialized;

jest/setupTests.js

-2
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,3 @@ jest.mock("@linaria/react", () => {
2121
jest.mock("@linaria/core", () => ({
2222
css: jest.fn(() => ""),
2323
}));
24-
25-
global.DEFAULT_LOCALE = "en-US";

0 commit comments

Comments
 (0)