Skip to content

Commit

Permalink
Merge pull request #14 from DeKal/add-multi-language
Browse files Browse the repository at this point in the history
Add localize component
  • Loading branch information
DeKal authored Nov 26, 2019
2 parents 8573a45 + ce5b80a commit 965caed
Show file tree
Hide file tree
Showing 16 changed files with 1,168 additions and 277 deletions.
51 changes: 51 additions & 0 deletions localize/LocalizedComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react'
import PropTypes from 'prop-types'
import { renderToStaticMarkup } from 'react-dom/server'
import { withLocalize } from 'react-localize-redux'
import enTrans from '~/public/translations/en.json'
import vnTrans from '~/public/translations/vn.json'
import { EN } from '~/consts/langs'

const onMissingTranslation = ({ translationId }) => {
return translationId
}
const defaultLanguage = EN

class LocalizedComponent extends React.Component {
constructor(props) {
super(props)

const languages = ['en', 'vn']

this.props.initialize({
languages,
options: {
renderToStaticMarkup,
defaultLanguage,
onMissingTranslation,
renderInnerHtml: true
}
})

this.props.addTranslationForLanguage(enTrans, 'en')
this.props.addTranslationForLanguage(vnTrans, 'vn')
}

render() {
return this.props.children
}

componentDidMount() {
const lang = window.localStorage.getItem('lang') || defaultLanguage
this.props.setActiveLanguage(lang)
}
}

LocalizedComponent.propTypes = {
initialize: PropTypes.func,
addTranslationForLanguage: PropTypes.func,
children: PropTypes.element,
setActiveLanguage: PropTypes.func
}

export default withLocalize(LocalizedComponent)
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"react": "16.12.0",
"react-dom": "16.12.0",
"react-icons": "^3.8.0",
"recompose": "0.30.0",
"react-localize-redux": "^3.5.3",
"styled-components": "4.4.1"
},
"devDependencies": {
Expand All @@ -39,8 +39,8 @@
"danger": "9.2.8",
"enzyme": "3.10.0",
"enzyme-adapter-react-16": "1.15.1",
"eslint": "6.7.0",
"enzyme-to-json": "^3.4.3",
"eslint": "6.7.0",
"eslint-plugin-prettier": "3.1.1",
"eslint-plugin-react": "7.16.0",
"fs": "0.0.2",
Expand Down
8 changes: 7 additions & 1 deletion pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import App from 'next/app'
import React from 'react'
import { ThemeProvider } from 'styled-components/macro'
import { LocalizeProvider } from 'react-localize-redux'
import LocalizedComponent from '~/localize/LocalizedComponent'
import { IconContext } from 'react-icons/lib/'

import theme from '~/views/theme'
Expand All @@ -14,7 +16,11 @@ export default class MyApp extends App {
return (
<IconContext.Provider value={{ style: { verticalAlign: 'middle' } }}>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
<LocalizeProvider>
<LocalizedComponent>
<Component {...pageProps} />
</LocalizedComponent>
</LocalizeProvider>
</ThemeProvider>
</IconContext.Provider>
)
Expand Down
11 changes: 11 additions & 0 deletions public/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"english": "english",
"vietnamese": "vietnamese",
"Menu": "Menu",
"Home": "Home",
"About": "About",
"Experiences": "Experiences",
"Certifications": "Certifications",
"Projects": "Projects",
"Contacts": "Contacts"
}
11 changes: 11 additions & 0 deletions public/translations/vn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"english": "Tiếng Anh",
"vietnamese": "Tiếng Việt",
"Menu": "Mục lục",
"Home": "Trang chủ",
"About": "Về tôi",
"Experiences": "Kinh nghiệm",
"Certifications": "Chứng chỉ",
"Projects": "Dự án",
"Contacts": "Liên lạc"
}
6 changes: 4 additions & 2 deletions views/components/nav/NavHeader.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react'
import styled from 'styled-components/macro'
import PropTypes from 'prop-types'
import { Translate } from 'react-localize-redux'
import { GiHamburgerMenu } from 'react-icons/gi'
import { MdClose } from 'react-icons/md'
import NavLang from '~/views/components/nav/NavLang'
import PropTypes from 'prop-types'

const NavHeader = ({ isShowNavContent, switchNav }) => (
<NavContainer className="first-nav">
Expand All @@ -15,7 +16,8 @@ const NavHeader = ({ isShowNavContent, switchNav }) => (
onClick={() => switchNav(!isShowNavContent)}
href="#"
>
{!isShowNavContent ? <HamburgerIcon /> : <CloseIcon />} Menu
{!isShowNavContent ? <HamburgerIcon /> : <CloseIcon />}{' '}
<Translate id="Menu" />
</NavControl>
</div>
</NavContainer>
Expand Down
7 changes: 5 additions & 2 deletions views/components/nav/NavItem.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components/macro'
import { Translate } from 'react-localize-redux'

const NavItem = ({ page, isSelected, setSelectedPage }) => {
return isSelected ? (
<SelectedContainer>{page}</SelectedContainer>
<SelectedContainer>
<Translate id={page} />
</SelectedContainer>
) : (
<Container
data-test-id="nav-link"
Expand All @@ -13,7 +16,7 @@ const NavItem = ({ page, isSelected, setSelectedPage }) => {
setSelectedPage(page)
}}
>
{page}
<Translate id={page} />
</Container>
)
}
Expand Down
17 changes: 13 additions & 4 deletions views/components/nav/NavLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,36 @@ import React from 'react'
import styled from 'styled-components/macro'
import PropTypes from 'prop-types'
import { EN } from '~/consts/langs'
import { Translate, withLocalize } from 'react-localize-redux'

const NavLink = ({ lang, selectedLang, setSelectedLang }) => {
const NavLink = ({
lang,
selectedLang,
setSelectedLang,
setActiveLanguage
}) => {
return (
<Container
isSelected={selectedLang === lang}
onClick={() => {
setSelectedLang(lang)
setActiveLanguage(lang)
window.localStorage.setItem('lang', lang)
}}
>
{lang === EN ? 'english' : 'vietnamese'}
{lang === EN ? <Translate id="english" /> : <Translate id="vietnamese" />}
</Container>
)
}

NavLink.propTypes = {
lang: PropTypes.string,
selectedLang: PropTypes.string,
setSelectedLang: PropTypes.func
setSelectedLang: PropTypes.func,
setActiveLanguage: PropTypes.func
}

export default NavLink
export default withLocalize(NavLink)

const Container = styled.a`
color: ${props =>
Expand Down
2 changes: 0 additions & 2 deletions views/components/nav/__test__/NavItem.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ describe('Nav Item', () => {
const tree = shallowWithTheme(
<NavItem page={'Home'} isSelected setSelectedPage={setSelectedPage} />
)
expect(tree.text()).toMatch('Home')
expect(tree).toMatchSnapshot()
})

Expand All @@ -19,7 +18,6 @@ describe('Nav Item', () => {
const tree = shallowWithTheme(
<NavItem page={'Home'} setSelectedPage={setSelectedPage} />
)
expect(tree.text()).toMatch('Home')
expect(tree).toMatchSnapshot()
})

Expand Down
23 changes: 17 additions & 6 deletions views/components/nav/__test__/NavLink.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import * as React from 'react'
import { shallowWithTheme } from '~/utils/withThemeProviders'
import { mountWithTheme } from '~/utils/withThemeProviders'
import NavLink from '~/views/components/nav/NavLink'
import { EN, VN } from '~/consts/langs'

describe('Nav Link', () => {
it('should render with English selected', function() {
const wrap = shallowWithTheme(<NavLink lang={EN} selectedLang={EN} />)
const wrap = mountWithTheme(<NavLink lang={EN} selectedLang={EN} />)
expect(wrap).toMatchSnapshot()
})

it('should render with Vietnamese selected', function() {
const wrap = shallowWithTheme(<NavLink lang={VN} selectedLang={VN} />)
const wrap = mountWithTheme(<NavLink lang={VN} selectedLang={VN} />)
expect(wrap).toMatchSnapshot()
})

it('should change Language when clicking', function() {
const setSelectedLang = jest.fn()
const wrap = shallowWithTheme(
<NavLink lang={VN} selectedLang={EN} setSelectedLang={setSelectedLang} />
const setActiveLanguage = jest.fn()
const wrap = mountWithTheme(
<NavLink
lang={VN}
selectedLang={EN}
setSelectedLang={setSelectedLang}
setActiveLanguage={setActiveLanguage}
/>
)
wrap.simulate('click')
expect(wrap).toMatchSnapshot()

expect(setSelectedLang.mock.calls.length).toEqual(1)
expect(setSelectedLang).toHaveBeenCalledWith(VN);
expect(setSelectedLang).toHaveBeenCalledWith(VN)

expect(setActiveLanguage.mock.calls.length).toEqual(1)
expect(setActiveLanguage).toHaveBeenCalledWith(VN)
})
})
Loading

0 comments on commit 965caed

Please sign in to comment.