Skip to content

Commit

Permalink
feat: add internationalization support
Browse files Browse the repository at this point in the history
  • Loading branch information
mistakia committed Feb 17, 2024
1 parent cd9510c commit 0bb60e4
Show file tree
Hide file tree
Showing 15 changed files with 211 additions and 3 deletions.
3 changes: 2 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ module.exports = {
'@pages': './src/views/pages',
'@core': './src/core',
'@components': './src/views/components',
'@styles': './src/styles'
'@styles': './src/styles',
'@i18n': './src/i18n'
}
}
],
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"fetch-cheerio-object": "^1.3.0",
"front-matter": "^4.0.2",
"fs-extra": "^11.1.1",
"i18next": "^23.8.2",
"jsonwebtoken": "^9.0.1",
"knex": "^0.95.15",
"markdown-it": "^12.3.2",
Expand All @@ -114,6 +115,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-i18next": "^14.0.5",
"react-redux": "^7.2.9",
"react-router": "^5.3.4",
"redux-saga": "^1.2.3",
Expand Down
10 changes: 10 additions & 0 deletions src/core/i18n/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const i18nActions = {
CHANGE_LOCALE: 'CHANGE_LOCALE',

change_locale: (locale) => ({
type: i18nActions.change_locale,
payload: {
locale
}
})
}
3 changes: 3 additions & 0 deletions src/core/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { i18nActions } from './actions'
export { i18nReducer } from './reducer'
export { i18nSagas } from './sagas'
17 changes: 17 additions & 0 deletions src/core/i18n/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Record } from 'immutable'

import { i18nActions } from './actions'

const initialState = new Record({
locale: 'en'
})

export function i18nReducer(state = initialState(), { payload, type }) {
switch (type) {
case i18nActions.CHANGE_LANGUAGE:
return state.set('locale', payload.locale)

default:
return state
}
}
38 changes: 38 additions & 0 deletions src/core/i18n/sagas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { takeLatest, put, fork } from 'redux-saga/effects'
import i18n from 'i18next'

import { localStorageAdapter } from '@core/utils'
import { appActions } from '@core/app/actions'
import { i18nActions } from './actions'

export function* init() {
const locale = localStorageAdapter.getItem('locale')
if (locale) {
yield put(i18nActions.change_locale(locale))
}

// TODO detect user locale
}

export function ChangeLocale({ payload }) {
localStorageAdapter.setItem('locale', payload.locale)
i18n.changeLanguage(payload.locale)
}

//= ====================================
// WATCHERS
// -------------------------------------

export function* watchInitApp() {
yield takeLatest(appActions.INIT_APP, init)
}

export function* watchChangeLocale() {
yield takeLatest(i18nActions.CHANGE_LOCALE, ChangeLocale)
}

//= ====================================
// ROOT
// -------------------------------------

export const i18nSagas = [fork(watchInitApp), fork(watchChangeLocale)]
4 changes: 3 additions & 1 deletion src/core/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { networkReducer } from './network'
import { notificationReducer } from './notifications'
import { postsReducer } from './posts'
import { postlistsReducer } from './postlists'
import { i18nReducer } from './i18n'

const rootReducer = (history) =>
combineReducers({
Expand All @@ -28,7 +29,8 @@ const rootReducer = (history) =>
network: networkReducer,
notification: notificationReducer,
posts: postsReducer,
postlists: postlistsReducer
postlists: postlistsReducer,
i18n: i18nReducer
})

export default rootReducer
4 changes: 3 additions & 1 deletion src/core/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { githubIssuesSagas } from './github-issues'
import { ledgerSagas } from './ledger'
import { networkSagas } from './network'
import { postlistSagas } from './postlists'
import { i18nSagas } from './i18n'

export default function* rootSage() {
yield all([
Expand All @@ -22,6 +23,7 @@ export default function* rootSage() {
...githubIssuesSagas,
...ledgerSagas,
...networkSagas,
...postlistSagas
...postlistSagas,
...i18nSagas
])
}
19 changes: 19 additions & 0 deletions src/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { initReactI18next } from 'react-i18next'
import i18n from 'i18next'

i18n.use(initReactI18next).init({
// detection
debug: true,
resources: {
en: {
translation: {
'Welcome to React': 'Welcome to React and react-i18next'
}
}
},
lng: 'en',
fallbackLng: 'en'
// supportedLngs
})

export default i18n
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Needed for redux-saga es6 generator support
import '@babel/polyfill'

import '@i18n'
import React from 'react'
import { render } from 'react-dom'

Expand Down
32 changes: 32 additions & 0 deletions src/views/components/change-locale/change-locale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import PropTypes from 'prop-types'
import FormControl from '@material-ui/core/FormControl'
import Select from '@material-ui/core/Select'
import MenuItem from '@material-ui/core/MenuItem'

import './change-locale.styl'

export default function ChangeLocale({ change_locale, locale }) {
return (
<FormControl className='change-locale'>
<Select
labelId='change-locale'
id='change-locale'
value={locale}
onChange={(event) => change_locale(event.target.value)}>
<MenuItem value='en'>English</MenuItem>
<MenuItem value='es'>Español</MenuItem>
<MenuItem value='fr'>Français</MenuItem>
<MenuItem value='it'>Italiano</MenuItem>
<MenuItem value='de'>Deutsch</MenuItem>
<MenuItem value='nl'>Nederlands</MenuItem>
<MenuItem value='ru'>Русский</MenuItem>
</Select>
</FormControl>
)
}

ChangeLocale.propTypes = {
change_locale: PropTypes.func.isRequired,
locale: PropTypes.string.isRequired
}
Empty file.
17 changes: 17 additions & 0 deletions src/views/components/change-locale/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { connect } from 'react-redux'
import { createSelector } from 'reselect'

import { i18nActions } from '@core/i18n'

import ChangeLocale from './change-locale'

const mapStateToProps = createSelector(
(state) => state.getIn(['i18n', 'locale']),
(locale) => ({ locale })
)

const mapDispatchToProps = {
change_locale: i18nActions.change_locale
}

export default connect(mapStateToProps, mapDispatchToProps)(ChangeLocale)
3 changes: 3 additions & 0 deletions src/views/components/menu/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import HomeIcon from '@material-ui/icons/Home'

import SearchBar from '@components/search-bar'
import history from '@core/history'
import ChangeLocale from '@components/change-locale'

import './menu.styl'

Expand Down Expand Up @@ -143,6 +144,7 @@ export default class Menu extends React.Component {
disableDiscovery={iOS}
anchor='top'>
<MenuSections />
<ChangeLocale />
</SwipeableDrawer>
{!hide_speed_dial && (
<SpeedDial
Expand Down Expand Up @@ -179,6 +181,7 @@ export default class Menu extends React.Component {
)}
{!hideSearch && <SearchBar />}
{!hide && <MenuSections />}
<ChangeLocale />
</div>
</div>
)
Expand Down
61 changes: 61 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,15 @@ __metadata:
languageName: node
linkType: hard

"@babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9":
version: 7.23.9
resolution: "@babel/runtime@npm:7.23.9"
dependencies:
regenerator-runtime: ^0.14.0
checksum: 6bbebe8d27c0c2dd275d1ac197fc1a6c00e18dab68cc7aaff0adc3195b45862bae9c4cc58975629004b0213955b2ed91e99eccb3d9b39cabea246c657323d667
languageName: node
linkType: hard

"@babel/template@npm:^7.22.15, @babel/template@npm:^7.23.9":
version: 7.23.9
resolution: "@babel/template@npm:7.23.9"
Expand Down Expand Up @@ -9646,6 +9655,15 @@ __metadata:
languageName: node
linkType: hard

"html-parse-stringify@npm:^3.0.1":
version: 3.0.1
resolution: "html-parse-stringify@npm:3.0.1"
dependencies:
void-elements: 3.1.0
checksum: 334fdebd4b5c355dba8e95284cead6f62bf865a2359da2759b039db58c805646350016d2017875718bc3c4b9bf81a0d11be5ee0cf4774a3a5a7b97cde21cfd67
languageName: node
linkType: hard

"html-webpack-plugin@npm:^5.5.3":
version: 5.5.3
resolution: "html-webpack-plugin@npm:5.5.3"
Expand Down Expand Up @@ -9866,6 +9884,15 @@ __metadata:
languageName: node
linkType: hard

"i18next@npm:^23.8.2":
version: 23.8.2
resolution: "i18next@npm:23.8.2"
dependencies:
"@babel/runtime": ^7.23.2
checksum: c20e68c6c216bfcedc16d8d8b1ee545423e26e84ace36b699f936ec8cf1b4df8ee2ae093e7a3e444a9cb5931ca76698ae1a80d31691aa4153bcc804394e0019e
languageName: node
linkType: hard

"iconv-lite@npm:0.4.24":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
Expand Down Expand Up @@ -14641,6 +14668,24 @@ __metadata:
languageName: node
linkType: hard

"react-i18next@npm:^14.0.5":
version: 14.0.5
resolution: "react-i18next@npm:14.0.5"
dependencies:
"@babel/runtime": ^7.23.9
html-parse-stringify: ^3.0.1
peerDependencies:
i18next: ">= 23.2.3"
react: ">= 16.8.0"
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
checksum: 54fe5ffd887d633852ea7e82e98b6ef057facf45dec512469dd0e43ae64d9450d2bafe7c85c87fd650cf6dad1bf81727a89fba23af0508b7a806153d459fc5cc
languageName: node
linkType: hard

"react-immutable-proptypes@npm:^2.2.0":
version: 2.2.0
resolution: "react-immutable-proptypes@npm:2.2.0"
Expand Down Expand Up @@ -15013,6 +15058,13 @@ __metadata:
languageName: node
linkType: hard

"regenerator-runtime@npm:^0.14.0":
version: 0.14.1
resolution: "regenerator-runtime@npm:0.14.1"
checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38
languageName: node
linkType: hard

"regenerator-transform@npm:^0.15.2":
version: 0.15.2
resolution: "regenerator-transform@npm:0.15.2"
Expand Down Expand Up @@ -15421,6 +15473,7 @@ __metadata:
html-inline-script-webpack-plugin: ^2.0.3
html-loader: ^2.1.2
html-webpack-plugin: ^5.5.3
i18next: ^23.8.2
image-webpack-loader: ^7.0.1
ipfs-deploy: ^12.0.1
jsonwebtoken: ^9.0.1
Expand All @@ -15446,6 +15499,7 @@ __metadata:
react: ^17.0.2
react-dom: ^17.0.2
react-helmet: ^6.1.0
react-i18next: ^14.0.5
react-immutable-proptypes: ^2.2.0
react-redux: ^7.2.9
react-router: ^5.3.4
Expand Down Expand Up @@ -17529,6 +17583,13 @@ __metadata:
languageName: node
linkType: hard

"void-elements@npm:3.1.0":
version: 3.1.0
resolution: "void-elements@npm:3.1.0"
checksum: 0390f818107fa8fce55bb0a5c3f661056001c1d5a2a48c28d582d4d847347c2ab5b7f8272314cac58acf62345126b6b09bea623a185935f6b1c3bbce0dfd7f7f
languageName: node
linkType: hard

"watchpack@npm:^2.4.0":
version: 2.4.0
resolution: "watchpack@npm:2.4.0"
Expand Down

0 comments on commit 0bb60e4

Please sign in to comment.