From aabf31661a81400261bcf2262f5c7b3ad2752503 Mon Sep 17 00:00:00 2001
From: mistakia <1823355+mistakia@users.noreply.github.com>
Date: Sat, 17 Feb 2024 08:29:35 -0500
Subject: [PATCH] feat: add internationalization support
---
babel.config.js | 3 +-
package.json | 2 +
src/core/app/actions.js | 5 +-
src/core/i18n/actions.js | 10 ++
src/core/i18n/index.js | 3 +
src/core/i18n/reducer.js | 17 +++
src/core/i18n/sagas.js | 37 +++++
src/core/reducers.js | 4 +-
src/core/sagas.js | 4 +-
src/i18n/index.js | 28 ++++
src/index.js | 1 +
src/views/components/app/app.js | 3 +-
.../components/change-locale/change-locale.js | 32 +++++
.../change-locale/change-locale.styl | 0
src/views/components/change-locale/index.js | 17 +++
src/views/components/menu/menu.js | 128 +++++++++---------
yarn.lock | 61 +++++++++
17 files changed, 284 insertions(+), 71 deletions(-)
create mode 100644 src/core/i18n/actions.js
create mode 100644 src/core/i18n/index.js
create mode 100644 src/core/i18n/reducer.js
create mode 100644 src/core/i18n/sagas.js
create mode 100644 src/i18n/index.js
create mode 100644 src/views/components/change-locale/change-locale.js
create mode 100644 src/views/components/change-locale/change-locale.styl
create mode 100644 src/views/components/change-locale/index.js
diff --git a/babel.config.js b/babel.config.js
index fbe35bd0..a1ebc1b4 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -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'
}
}
],
diff --git a/package.json b/package.json
index 28b85565..897d0435 100644
--- a/package.json
+++ b/package.json
@@ -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",
@@ -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",
diff --git a/src/core/app/actions.js b/src/core/app/actions.js
index e178832a..c671f3ee 100644
--- a/src/core/app/actions.js
+++ b/src/core/app/actions.js
@@ -1,11 +1,12 @@
export const appActions = {
INIT_APP: 'INIT_APP',
- init: ({ token, key }) => ({
+ init: ({ token, key, locale }) => ({
type: appActions.INIT_APP,
payload: {
token,
- key
+ key,
+ locale
}
})
}
diff --git a/src/core/i18n/actions.js b/src/core/i18n/actions.js
new file mode 100644
index 00000000..4e968253
--- /dev/null
+++ b/src/core/i18n/actions.js
@@ -0,0 +1,10 @@
+export const i18nActions = {
+ CHANGE_LOCALE: 'CHANGE_LOCALE',
+
+ change_locale: (locale) => ({
+ type: i18nActions.CHANGE_LOCALE,
+ payload: {
+ locale
+ }
+ })
+}
diff --git a/src/core/i18n/index.js b/src/core/i18n/index.js
new file mode 100644
index 00000000..9cb917b1
--- /dev/null
+++ b/src/core/i18n/index.js
@@ -0,0 +1,3 @@
+export { i18nActions } from './actions'
+export { i18nReducer } from './reducer'
+export { i18nSagas } from './sagas'
diff --git a/src/core/i18n/reducer.js b/src/core/i18n/reducer.js
new file mode 100644
index 00000000..1891169f
--- /dev/null
+++ b/src/core/i18n/reducer.js
@@ -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_LOCALE:
+ return state.set('locale', payload.locale)
+
+ default:
+ return state
+ }
+}
diff --git a/src/core/i18n/sagas.js b/src/core/i18n/sagas.js
new file mode 100644
index 00000000..06135e04
--- /dev/null
+++ b/src/core/i18n/sagas.js
@@ -0,0 +1,37 @@
+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({ payload }) {
+ if (payload.locale) {
+ yield put(i18nActions.change_locale(payload.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)]
diff --git a/src/core/reducers.js b/src/core/reducers.js
index 6c7a6b4e..6304fc70 100644
--- a/src/core/reducers.js
+++ b/src/core/reducers.js
@@ -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({
@@ -28,7 +29,8 @@ const rootReducer = (history) =>
network: networkReducer,
notification: notificationReducer,
posts: postsReducer,
- postlists: postlistsReducer
+ postlists: postlistsReducer,
+ i18n: i18nReducer
})
export default rootReducer
diff --git a/src/core/sagas.js b/src/core/sagas.js
index 237db53f..ebaf63c7 100644
--- a/src/core/sagas.js
+++ b/src/core/sagas.js
@@ -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([
@@ -22,6 +23,7 @@ export default function* rootSage() {
...githubIssuesSagas,
...ledgerSagas,
...networkSagas,
- ...postlistSagas
+ ...postlistSagas,
+ ...i18nSagas
])
}
diff --git a/src/i18n/index.js b/src/i18n/index.js
new file mode 100644
index 00000000..6fa8f984
--- /dev/null
+++ b/src/i18n/index.js
@@ -0,0 +1,28 @@
+import { initReactI18next } from 'react-i18next'
+import i18n from 'i18next'
+
+i18n.use(initReactI18next).init({
+ // detection
+ debug: true,
+ resources: {
+ en: {
+ translation: {
+ menu: {
+ introduction: 'Introduction'
+ }
+ }
+ },
+ es: {
+ translation: {
+ menu: {
+ introduction: 'Introducción'
+ }
+ }
+ }
+ },
+ lng: 'en',
+ fallbackLng: 'en'
+ // supportedLngs
+})
+
+export default i18n
diff --git a/src/index.js b/src/index.js
index a587c113..28baef2f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -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'
diff --git a/src/views/components/app/app.js b/src/views/components/app/app.js
index 5ae1193f..61685dc5 100644
--- a/src/views/components/app/app.js
+++ b/src/views/components/app/app.js
@@ -15,7 +15,8 @@ export default class App extends React.Component {
async componentDidMount() {
const token = await localStorageAdapter.getItem('token')
const key = await localStorageAdapter.getItem('key')
- this.props.init({ token, key })
+ const locale = await localStorageAdapter.getItem('locale')
+ this.props.init({ token, key, locale })
this.props.getRepresentatives()
this.props.getNetworkStats()
this.props.getGithubEvents()
diff --git a/src/views/components/change-locale/change-locale.js b/src/views/components/change-locale/change-locale.js
new file mode 100644
index 00000000..cf9b3f29
--- /dev/null
+++ b/src/views/components/change-locale/change-locale.js
@@ -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 (
+