Skip to content

Commit 663da58

Browse files
committed
Feature(frontend): add i18n support
Closes #345
1 parent 357d3a0 commit 663da58

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+842
-146
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
* [x] [react-redux](https://github.com/reactjs/react-redux) - the official react bindings for [redux 4](https://github.com/reactjs/redux) (a predictable state container for js apps)
4040
* [x] [react-saga](https://github.com/redux-saga/redux-saga/) - make redux asynchronous flows easy to read, write and test, the replacement for [redux-thunk](https://github.com/reduxjs/redux-thunk)
4141
* [x] [connected-react-router](https://github.com/supasate/connected-react-router) - a redux binding for react-router 4, the replacement for [react-router-redux v5](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux)
42+
* [x] [react-loadable](https://github.com/jamiebuilds/react-loadable) - better user experience for dynamic loading components
43+
* [x] [react-i18next](https://github.com/i18next/react-i18next) - internationalization for react done right
4244
* [x] [immutable.js](https://github.com/facebook/immutable-js/) - persistent Immutable data structures for react redux state management
4345
* [x] [editorconfig](http://editorconfig.org/) - maintain consistent coding styles between different editors and IDEs
4446
* [x] [eslint](http://eslint.org/) - lint javascript files (.js, .jsx)

frontend/src/App.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { ConnectedRouter } from 'connected-react-router';
22
import { History } from 'history';
33
import * as React from 'react';
4+
import { I18nextProvider } from 'react-i18next';
45
import { Provider } from 'react-redux';
56
import { Store } from 'redux';
67

8+
import i18n from 'i18n';
79
import router from 'router';
810
import { IGlobalState } from 'types/global';
911

@@ -13,9 +15,11 @@ interface IAppProps {
1315
}
1416

1517
export default (props: IAppProps) => (
16-
<Provider store={props.store}>
17-
<ConnectedRouter history={props.history}>
18-
{router}
19-
</ConnectedRouter>
20-
</Provider>
18+
<I18nextProvider i18n={i18n}>
19+
<Provider store={props.store}>
20+
<ConnectedRouter history={props.history}>
21+
{router}
22+
</ConnectedRouter>
23+
</Provider>
24+
</I18nextProvider>
2125
);
Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import * as React from 'react';
2+
import { InjectedI18nProps, InjectedTranslateProps, translate } from 'react-i18next';
23
import { Link } from 'react-router-dom';
34

4-
import { upperCaseFirstChar } from 'utils';
5+
import i18ns from './i18n';
56

6-
interface IDropdownProps {
7+
interface IDropdownProps extends InjectedI18nProps, InjectedTranslateProps {
78
id: string;
89
dropdownLists: string[];
910
}
@@ -12,15 +13,30 @@ const dropdownConfig: Partial<M.DropdownOptions> = {
1213
coverTrigger: false,
1314
};
1415

15-
export default class Dropdown extends React.Component<IDropdownProps> {
16+
class Dropdown extends React.Component<IDropdownProps> {
17+
constructor(props: IDropdownProps) {
18+
super(props);
19+
this.loadI18ns();
20+
}
21+
22+
public loadI18ns() {
23+
const { i18n } = this.props;
24+
for (const key in i18ns) {
25+
if (i18ns.hasOwnProperty(key)) {
26+
i18n.addResourceBundle(key, 'Dropdown', i18ns[key]);
27+
}
28+
}
29+
}
30+
1631
public componentDidMount() {
1732
const elems = document.querySelectorAll('.dropdown-button');
1833
M.Dropdown.init(elems, dropdownConfig);
1934
}
2035

2136
public render() {
37+
const { t } = this.props;
2238
const links = this.props.dropdownLists.map((key) =>
23-
<li key={key}><Link to={`/${key}`}>{upperCaseFirstChar(key)}</Link></li>,
39+
<li key={key}><Link to={`/${key}`}>{t(key)}</Link></li>,
2440
);
2541
return (
2642
<ul id={this.props.id} className='dropdown-content'>
@@ -29,3 +45,5 @@ export default class Dropdown extends React.Component<IDropdownProps> {
2945
);
3046
}
3147
}
48+
49+
export default translate('Dropdown')(Dropdown);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"parallax": "Parallax"
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const en = require('./en.json');
2+
const jp = require('./jp.json');
3+
const zh = require('./zh.json');
4+
5+
const i18ns: { [id: string]: string; } = {
6+
en,
7+
jp,
8+
zh,
9+
};
10+
11+
export default i18ns;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"parallax": "視差"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"parallax": "视差"
3+
}
Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,55 @@
11
import * as React from 'react';
2+
import { InjectedI18nProps, InjectedTranslateProps, translate } from 'react-i18next';
3+
4+
import i18ns from './i18n';
5+
6+
interface IFooterProps extends InjectedI18nProps, InjectedTranslateProps { }
7+
8+
class Footer extends React.Component<IFooterProps> {
9+
constructor(props: IFooterProps) {
10+
super(props);
11+
this.loadI18ns();
12+
}
13+
14+
public loadI18ns() {
15+
const { i18n } = this.props;
16+
for (const key in i18ns) {
17+
if (i18ns.hasOwnProperty(key)) {
18+
i18n.addResourceBundle(key, 'Footer', i18ns[key]);
19+
}
20+
}
21+
}
222

3-
export default class Footer extends React.Component {
423
public render() {
24+
const { t } = this.props;
525
return (
626
<footer className='page-footer'>
727
<div className='container'>
828
<div className='row'>
929
<div className='col l6 s12'>
10-
<h5 className='white-text'>Footer Content</h5>
11-
<p className='grey-text text-lighten-4'>
12-
You can use rows and columns here to organize your footer content.
13-
</p>
30+
<h5 className='white-text'>{t('footer-title')}</h5>
31+
<p className='grey-text text-lighten-4'>{t('footer-content')}</p>
1432
</div>
15-
<div className='col l4 offset-l2 s12'>
16-
<h5 className='white-text'>Links</h5>
33+
<div className='col l3 offset-l3 s12'>
34+
<h5 className='white-text'>{t('links')}</h5>
1735
<ul>
18-
<li><a className='grey-text text-lighten-3' href='#'>Link 1</a></li>
19-
<li><a className='grey-text text-lighten-3' href='#'>Link 2</a></li>
20-
<li><a className='grey-text text-lighten-3' href='#'>Link 3</a></li>
21-
<li><a className='grey-text text-lighten-3' href='#'>Link 4</a></li>
36+
<li><a className='grey-text text-lighten-3' href='#'>{t('link-1')}</a></li>
37+
<li><a className='grey-text text-lighten-3' href='#'>{t('link-2')}</a></li>
38+
<li><a className='grey-text text-lighten-3' href='#'>{t('link-3')}</a></li>
39+
<li><a className='grey-text text-lighten-3' href='#'>{t('link-4')}</a></li>
2240
</ul>
2341
</div>
2442
</div>
2543
</div>
2644
<div className='footer-copyright'>
2745
<div className='container'>
28-
© 2017 Copyright Text
29-
<a className='grey-text text-lighten-4 right' href='#'>More Links</a>
46+
© 2017 Copyright <a className='grey-text text-lighten-4' href='https://github.com/Armour'>Armour</a>
47+
<a className='grey-text text-lighten-4 right' href='#'>{t('more-links')}</a>
3048
</div>
3149
</div>
3250
</footer>
3351
);
3452
}
3553
}
54+
55+
export default translate('Footer')(Footer);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"footer-title": "Footer Content",
3+
"footer-content": "You can use rows and columns here to organize your footer content.",
4+
"links": "Links",
5+
"link-1": "Link 1",
6+
"link-2": "Link 2",
7+
"link-3": "Link 3",
8+
"link-4": "Link 4",
9+
"more-links": "More Links"
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const en = require('./en.json');
2+
const jp = require('./jp.json');
3+
const zh = require('./zh.json');
4+
5+
const i18ns: { [id: string]: string; } = {
6+
en,
7+
jp,
8+
zh,
9+
};
10+
11+
export default i18ns;

0 commit comments

Comments
 (0)