Skip to content

Commit 9ae7b16

Browse files
committed
feat: display translations from store
1 parent 7ca5fb1 commit 9ae7b16

5 files changed

Lines changed: 146 additions & 32 deletions

File tree

src/app/components/Header.tsx

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import * as React from "react";
2+
import {connect} from "react-redux";
3+
import {createSelector} from "reselect";
24
import {style} from "typestyle";
5+
import {Translator} from "../models/Translator";
6+
import {ITranslator} from "../models/TranslatorInterfaces";
7+
import {IStore} from "../redux/IStore";
8+
import {translationsSelector} from "../selectors/translationsSelector";
39
import {Link} from "./Link";
410

511
const classNames = {
@@ -19,13 +25,49 @@ const classNames = {
1925
})
2026
};
2127

22-
export const Header = () => (
23-
<nav className={classNames.nav}>
24-
<ul>
25-
<li><Link name="home">Home</Link></li>
26-
<li><Link name="about">About Us</Link></li>
27-
<li><Link name="counter">Counter</Link></li>
28-
<li><Link name="stars">Stars</Link></li>
29-
</ul>
30-
</nav>
28+
interface IStateToProps {
29+
translations: {
30+
aboutUs: string;
31+
counter: string;
32+
home: string;
33+
stars: string;
34+
};
35+
}
36+
37+
class Header extends React.Component<IStateToProps> {
38+
public render(): JSX.Element {
39+
const {translations} = this.props;
40+
return (
41+
<nav className={classNames.nav}>
42+
<ul>
43+
<li><Link name="home">{translations.home}</Link></li>
44+
<li><Link name="about">{translations.aboutUs}</Link></li>
45+
<li><Link name="counter">{translations.counter}</Link></li>
46+
<li><Link name="stars">{translations.stars}</Link></li>
47+
</ul>
48+
</nav>
49+
);
50+
}
51+
}
52+
53+
const componentTranslationsSelector = createSelector(
54+
translationsSelector,
55+
(translations) => {
56+
const translator: ITranslator = new Translator(translations);
57+
return {
58+
aboutUs: translator.translate("About us"),
59+
counter: translator.translate("Counter"),
60+
home: translator.translate("Home"),
61+
stars: translator.translate("Stars")
62+
};
63+
}
3164
);
65+
66+
function mapStateToProps(state: Pick<IStore, "settings">): IStateToProps {
67+
return {
68+
translations: componentTranslationsSelector(state)
69+
};
70+
}
71+
72+
const connected = connect(mapStateToProps)(Header);
73+
export {connected as Header, Header as UnconnectedHeader};

src/app/containers/AboutPage.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,26 @@ interface IProps extends IStateToProps, IDispatchToProps {}
2727
class AboutPage extends React.Component<IProps> {
2828
constructor(props: IStateToProps & IDispatchToProps) {
2929
super(props);
30-
this.switchLanguage = this.switchLanguage.bind(this);
31-
}
32-
33-
public switchLanguage(): void {
34-
const language = this.props.language === "en" ? "de" : "en";
35-
this.props.setLanguage(language);
30+
this.handleLanguageChange = this.handleLanguageChange.bind(this);
3631
}
3732

3833
public render(): JSX.Element {
39-
const {language, translations: {aboutUs, change, currentLanguage}} = this.props;
34+
const {language, translations} = this.props;
4035
return (
4136
<div>
42-
<h3>{aboutUs}: {language}</h3>
43-
<button onClick={this.switchLanguage}>
44-
{change}
37+
<h3>{translations.aboutUs}: {language}</h3>
38+
<button onClick={this.handleLanguageChange}>
39+
{translations.change}
4540
</button>
46-
<h4>{currentLanguage}</h4>
41+
<h4>{translations.currentLanguage}</h4>
4742
</div>
4843
);
4944
}
45+
46+
private handleLanguageChange(): void {
47+
const language = this.props.language === "en" ? "de" : "en";
48+
this.props.setLanguage(language);
49+
}
5050
}
5151

5252
const componentTranslationsSelector = createSelector(

src/app/containers/CounterPage.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
import * as React from "react";
22
import {connect} from "react-redux";
33
import {Dispatch} from "redux";
4+
import {createSelector} from "reselect";
5+
import {Translator} from "../models/Translator";
6+
import {ITranslator} from "../models/TranslatorInterfaces";
47
import {IStore} from "../redux/IStore";
58
import {
69
decrement as decrementActionCreator,
710
increment as incrementActionCreator
811
} from "../redux/modules/counterActionCreators";
12+
import {translationsSelector} from "../selectors/translationsSelector";
913

1014
interface IStateToProps {
1115
count: number;
16+
translations: {
17+
counter: string;
18+
decrement: string;
19+
increment: string;
20+
};
1221
}
1322

1423
interface IDispatchToProps {
@@ -20,25 +29,38 @@ export interface IProps extends IStateToProps, IDispatchToProps {}
2029

2130
class CounterPage extends React.Component<IProps> {
2231
public render(): JSX.Element {
23-
const {count, decrement, increment} = this.props;
32+
const {count, decrement, increment, translations} = this.props;
2433
return (
2534
<div>
26-
<h4>Counter</h4>
35+
<h4>{translations.counter}</h4>
2736
<button name="incBtn" onClick={increment}>
28-
Increment
37+
{translations.increment}
2938
</button>
3039
<button name="decBtn" onClick={decrement} disabled={count <= 0}>
31-
Decrement
40+
{translations.increment}
3241
</button>
3342
<p>{count}</p>
3443
</div>
3544
);
3645
}
3746
}
3847

39-
function mapStateToProps(state: Pick<IStore, "counter">): IStateToProps {
48+
const componentTranslationsSelector = createSelector(
49+
translationsSelector,
50+
(translations) => {
51+
const translator: ITranslator = new Translator(translations);
52+
return {
53+
counter: translator.translate("Counter"),
54+
decrement: translator.translate("Decrement"),
55+
increment: translator.translate("Increment")
56+
};
57+
}
58+
);
59+
60+
function mapStateToProps(state: Pick<IStore, "counter" | "settings">): IStateToProps {
4061
return {
41-
count: state.counter.count
62+
count: state.counter.count,
63+
translations: componentTranslationsSelector(state)
4264
};
4365
}
4466

src/app/containers/HomePage.tsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import {color} from "csx";
22
import * as React from "react";
3+
import {connect} from "react-redux";
4+
import {createSelector} from "reselect";
35
import {stylesheet} from "typestyle";
6+
import {Translator} from "../models/Translator";
7+
import {ITranslator} from "../models/TranslatorInterfaces";
8+
import {IStore} from "../redux/IStore";
9+
import {translationsSelector} from "../selectors/translationsSelector";
410

511
const classNames = stylesheet({
612
container: {
@@ -9,13 +15,39 @@ const classNames = stylesheet({
915
}
1016
});
1117

12-
export class HomePage extends React.Component {
18+
interface IStateToProps {
19+
translations: {
20+
hello: string;
21+
};
22+
}
23+
24+
class HomePage extends React.Component<IStateToProps> {
1325
public render(): JSX.Element {
26+
const {translations} = this.props;
1427
return (
1528
<div className={classNames.container}>
1629
<img alt={"barbar"} src={require("../images/barbar.png")}/>
17-
<p>Hello</p>
30+
<p>{translations.hello}</p>
1831
</div>
1932
);
2033
}
2134
}
35+
36+
const componentTranslationsSelector = createSelector(
37+
translationsSelector,
38+
(translations) => {
39+
const translator: ITranslator = new Translator(translations);
40+
return {
41+
hello: translator.translate("Hello")
42+
};
43+
}
44+
);
45+
46+
function mapStateToProps(state: Pick<IStore, "settings">): IStateToProps {
47+
return {
48+
translations: componentTranslationsSelector(state)
49+
};
50+
}
51+
52+
const connected = connect(mapStateToProps)(HomePage);
53+
export {connected as HomePage, HomePage as UnconnectedHomePage};

src/app/containers/StarsPage.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import * as React from "react";
22
import {connect} from "react-redux";
33
import {Dispatch} from "redux";
4+
import {createSelector} from "reselect";
5+
import {Translator} from "../models/Translator";
6+
import {ITranslator} from "../models/TranslatorInterfaces";
47
import {IStore} from "../redux/IStore";
58
import {loadStarsCount as loadStarsActionCreator} from "../redux/modules/starsActionCreators";
9+
import {translationsSelector} from "../selectors/translationsSelector";
610

711
interface IStateToProps {
812
count: number;
913
error: string;
1014
loaded: boolean;
1115
pending: boolean;
16+
translations: {
17+
fetchingStars: string;
18+
};
1219
}
1320

1421
interface IDispatchToProps {
@@ -26,21 +33,32 @@ class StarsPage extends React.Component<IProps> {
2633
}
2734

2835
public render(): JSX.Element {
29-
const {count, error, pending} = this.props;
36+
const {count, error, pending, translations} = this.props;
3037
if (pending) {
31-
return <div>Fetching stars...</div>;
38+
return <div>{translations.fetchingStars}</div>;
3239
} else {
3340
return error ? <div>{error}</div> : <div>{count}</div>;
3441
}
3542
}
3643
}
3744

38-
function mapStateToProps(state: Pick<IStore, "stars">): IStateToProps {
45+
const componentTranslationsSelector = createSelector(
46+
translationsSelector,
47+
(translations) => {
48+
const translator: ITranslator = new Translator(translations);
49+
return {
50+
fetchingStars: translator.translate("Fetching stars...")
51+
};
52+
}
53+
);
54+
55+
function mapStateToProps(state: Pick<IStore, "settings" | "stars">): IStateToProps {
3956
return {
4057
count: state.stars.count,
4158
error: state.stars.error,
4259
loaded: state.stars.loaded,
43-
pending: state.stars.pending
60+
pending: state.stars.pending,
61+
translations: componentTranslationsSelector(state)
4462
};
4563
}
4664

0 commit comments

Comments
 (0)