Skip to content

Commit 4464a02

Browse files
authored
Merge pull request #1 from thaind97git/develop
Add i18n feature
2 parents dd270ea + f3fe646 commit 4464a02

File tree

17 files changed

+441
-45
lines changed

17 files changed

+441
-45
lines changed

README.md

+38-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ For Production:
7070
- [ ] Redux-saga
7171
- [x] Jest
7272
- [x] Axios
73-
- [x] I18n [Not completed]
73+
- [x] I18n
7474
- [x] React-router
7575
- [x] Alias
7676
- [x] Hot reload
@@ -139,6 +139,43 @@ For Production:
139139

140140
_- You should use [BEM](http://getbem.com/) to write css without conflict_
141141

142+
- Using i18n
143+
144+
- Create new json file at `src/locales/resources/<file-name/>.json`
145+
- Add content follow this format into json file
146+
```javascript
147+
{
148+
"en": {
149+
"name": "Name"
150+
},
151+
"vi": {
152+
"name": "Tên"
153+
}
154+
}
155+
```
156+
- update `src/locales/resources/index.ts` like this:
157+
158+
```javascript
159+
/*
160+
* you can use other name instead `user`
161+
* this name will be used as path to key
162+
*/
163+
import user from './<file-name/>.json
164+
165+
const mergeResource: IResource = {
166+
..., // others json
167+
user
168+
};
169+
```
170+
171+
- Now inside any where, you can access to key like this:
172+
173+
```javascript
174+
const { t } = useTranslation()
175+
176+
t('user.name') will be render "Name" for `en` and "Tên" for `vi`
177+
```
178+
142179
---
143180

144181
## Tips

config/@types/index.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ declare module '*.png' {
1515
}
1616

1717
declare module '*.json' {
18-
const content: string;
18+
const content: any;
1919
export default content;
2020
}
2121

+52
Loading

public/static/images/icon/en.svg

+62
Loading

public/static/images/icon/vi.svg

+45
Loading

src/components/select/index.tsx

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import useOutsideClick from '@/hooks/useOutsideClick';
2+
import React, { useRef, useState } from 'react';
3+
import ArrowDown from '@/static/images/icon/arrow-down.svg';
4+
5+
interface IOption {
6+
value: any;
7+
label: any;
8+
}
9+
10+
interface IProps {
11+
options: Array<IOption>;
12+
width?: number;
13+
onChange?: (option: IOption) => void;
14+
className?: string;
15+
}
16+
17+
const Select: React.FC<IProps> = ({
18+
options,
19+
width = 240,
20+
onChange,
21+
className,
22+
}) => {
23+
const [show, setShow] = useState<boolean>(false);
24+
const [option, setOption] = useState<IOption>(options[0]);
25+
const selectRef = useRef(null);
26+
useOutsideClick(selectRef, () => {
27+
show === true && setShow(false);
28+
});
29+
30+
function handleSelectDropdown(option: IOption) {
31+
const opt = options.find(opt => opt.value === option.value);
32+
33+
typeof onChange === 'function' && onChange(opt);
34+
setOption(opt);
35+
setShow(false);
36+
}
37+
return (
38+
<div
39+
ref={selectRef}
40+
style={{ width }}
41+
className={`dropdown ${className || ''}`}
42+
>
43+
<div onClick={() => setShow(true)} className="dropdown-select">
44+
<span className="dropdown-selected">{option.label}</span>
45+
<ArrowDown className={`dropdown-caret ${show ? 'up' : 'down'}`} />
46+
</div>
47+
<ul className={`dropdown-list ${show ? 'show' : ''}`}>
48+
{options.map(opt => (
49+
<li
50+
key={opt.value}
51+
onClick={() => handleSelectDropdown(opt)}
52+
className="dropdown-item"
53+
>
54+
{opt.label}
55+
</li>
56+
))}
57+
</ul>
58+
</div>
59+
);
60+
};
61+
62+
export default Select;

src/components/select/style.scss

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
.dropdown {
2+
color: $primary-color;
3+
width: 100%;
4+
position: relative;
5+
border-radius: 8px;
6+
.dropdown-caret {
7+
width: 12px;
8+
fill: $primary-color;
9+
10+
&.up {
11+
transform: rotate(180deg);
12+
}
13+
}
14+
.dropdown-select {
15+
background-color: white;
16+
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.1);
17+
padding: 1rem;
18+
border-radius: inherit;
19+
display: flex;
20+
align-items: center;
21+
justify-content: space-between;
22+
cursor: pointer;
23+
}
24+
.dropdown-select * {
25+
pointer-events: none;
26+
}
27+
.dropdown-list {
28+
position: absolute;
29+
top: 100%;
30+
left: 0;
31+
right: 0;
32+
margin-top: 0.4rem;
33+
background-color: white;
34+
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.1);
35+
padding: 1rem;
36+
border-radius: 8px;
37+
display: none;
38+
&::before {
39+
content: '';
40+
height: 1rem;
41+
position: absolute;
42+
top: 0;
43+
left: 0;
44+
right: 0;
45+
background-color: transparent;
46+
transform: translateY(-100%);
47+
}
48+
&.show {
49+
display: block;
50+
}
51+
52+
.dropdown-item {
53+
padding: 1rem;
54+
color: #47536b;
55+
transition: all 0.25s ease;
56+
border-radius: 8px;
57+
cursor: pointer;
58+
&:hover {
59+
color: $primary-color;
60+
background-color: #f1fbff;
61+
}
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)