Client - init localization w/ react-i18n - #40
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Translation } from 'react-i18next'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
@ -8,146 +9,153 @@ class NavBar extends React.PureComponent {
|
||||
render() {
|
||||
const { id, isAuthenticated, picture, username } = this.props
|
||||
return (
|
||||
<header>
|
||||
<nav className="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div className="container">
|
||||
<span className="navbar-brand">FitTrackee</span>
|
||||
<button
|
||||
className="navbar-toggler"
|
||||
type="button"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span className="navbar-toggler-icon" />
|
||||
</button>
|
||||
<div
|
||||
className="collapse navbar-collapse"
|
||||
id="navbarSupportedContent"
|
||||
>
|
||||
<ul className="navbar-nav mr-auto">
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/',
|
||||
}}
|
||||
<Translation>
|
||||
{t => (
|
||||
<header>
|
||||
<nav className="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div className="container">
|
||||
<span className="navbar-brand">FitTrackee</span>
|
||||
<button
|
||||
className="navbar-toggler"
|
||||
type="button"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span className="navbar-toggler-icon" />
|
||||
</button>
|
||||
<div
|
||||
className="collapse navbar-collapse"
|
||||
id="navbarSupportedContent"
|
||||
>
|
||||
<ul className="navbar-nav mr-auto">
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/',
|
||||
}}
|
||||
>
|
||||
{t('Dashboard')}
|
||||
</Link>
|
||||
</li>
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/history',
|
||||
}}
|
||||
>
|
||||
{t('Workouts')}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/statistics',
|
||||
}}
|
||||
>
|
||||
{t('Statistics')}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/add',
|
||||
}}
|
||||
>
|
||||
<strong>{t('Add workout')}</strong>
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{/* {user.admin && ( */}
|
||||
{/* <li className="nav-item"> */}
|
||||
{/* <Link */}
|
||||
{/* className="nav-link" */}
|
||||
{/* to={{ */}
|
||||
{/* pathname: '/admin', */}
|
||||
{/* }} */}
|
||||
{/* > */}
|
||||
{/* Admin */}
|
||||
{/* </Link> */}
|
||||
{/* </li> */}
|
||||
{/* )} */}
|
||||
</ul>
|
||||
{/* prettier-ignore */}
|
||||
<ul
|
||||
className="navbar-nav flex-row ml-md-auto d-none d-md-flex"
|
||||
>
|
||||
Dashboard
|
||||
</Link>
|
||||
</li>
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/history',
|
||||
}}
|
||||
>
|
||||
Workouts
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/statistics',
|
||||
}}
|
||||
>
|
||||
Statistics
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/add',
|
||||
}}
|
||||
>
|
||||
<strong>Add workout</strong>
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{/* {user.admin && ( */}
|
||||
{/* <li className="nav-item"> */}
|
||||
{/* <Link */}
|
||||
{/* className="nav-link" */}
|
||||
{/* to={{ */}
|
||||
{/* pathname: '/admin', */}
|
||||
{/* }} */}
|
||||
{/* > */}
|
||||
{/* Admin */}
|
||||
{/* </Link> */}
|
||||
{/* </li> */}
|
||||
{/* )} */}
|
||||
</ul>
|
||||
<ul className="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
{!isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/register',
|
||||
}}
|
||||
>
|
||||
Register
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{!isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/login',
|
||||
}}
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{picture === true && (
|
||||
<img
|
||||
alt="Avatar"
|
||||
src={`${apiUrl}users/${id}/picture?${Date.now()}`}
|
||||
className="img-fluid App-nav-profile-img"
|
||||
/>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/profile',
|
||||
}}
|
||||
>
|
||||
{username}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/logout',
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
{!isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/register',
|
||||
}}
|
||||
>
|
||||
{t('Register')}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{!isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/login',
|
||||
}}
|
||||
>
|
||||
{t('Login')}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{picture === true && (
|
||||
<img
|
||||
alt="Avatar"
|
||||
src={`${apiUrl}users/${id}/picture?${Date.now()}`}
|
||||
className="img-fluid App-nav-profile-img"
|
||||
/>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/profile',
|
||||
}}
|
||||
>
|
||||
{username}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/logout',
|
||||
}}
|
||||
>
|
||||
{t('Logout')}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
)}
|
||||
</Translation>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,21 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
||||
import { history } from '../../index'
|
||||
import { isRegistrationAllowed } from '../../utils'
|
||||
|
||||
export default function Form(props) {
|
||||
const { t } = useTranslation()
|
||||
const pageTitle = `${props.formType
|
||||
.charAt(0)
|
||||
.toUpperCase()}${props.formType.slice(1)}`
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>FitTrackee - {props.formType}</title>
|
||||
<title>FitTrackee - {t(props.formType)}</title>
|
||||
</Helmet>
|
||||
<h1 className="page-title">
|
||||
{`${props.formType.charAt(0).toUpperCase()}${props.formType.slice(1)}`}
|
||||
</h1>
|
||||
<h1 className="page-title">{t(pageTitle)}</h1>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-3" />
|
||||
@ -43,7 +46,7 @@ export default function Form(props) {
|
||||
<input
|
||||
className="form-control input-lg"
|
||||
name="username"
|
||||
placeholder="Enter a username"
|
||||
placeholder={t('Enter a username')}
|
||||
required
|
||||
type="text"
|
||||
value={props.userForm.username}
|
||||
@ -55,7 +58,7 @@ export default function Form(props) {
|
||||
<input
|
||||
className="form-control input-lg"
|
||||
name="email"
|
||||
placeholder="Enter an email address"
|
||||
placeholder={t('Enter an email address')}
|
||||
required
|
||||
type="email"
|
||||
value={props.userForm.email}
|
||||
@ -66,7 +69,7 @@ export default function Form(props) {
|
||||
<input
|
||||
className="form-control input-lg"
|
||||
name="password"
|
||||
placeholder="Enter a password"
|
||||
placeholder={t('Enter a password')}
|
||||
required
|
||||
type="password"
|
||||
value={props.userForm.password}
|
||||
@ -78,7 +81,7 @@ export default function Form(props) {
|
||||
<input
|
||||
className="form-control input-lg"
|
||||
name="password_conf"
|
||||
placeholder="Enter the password confirmation"
|
||||
placeholder={t('Enter the password confirmation')}
|
||||
required
|
||||
type="password"
|
||||
value={props.userForm.password_conf}
|
||||
@ -89,7 +92,7 @@ export default function Form(props) {
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-primary btn-lg btn-block"
|
||||
value="Submit"
|
||||
value={t('Submit')}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
|
31
fittrackee_client/src/i18n.js
Normal file
31
fittrackee_client/src/i18n.js
Normal file
@ -0,0 +1,31 @@
|
||||
import i18n from 'i18next'
|
||||
import LanguageDetector from 'i18next-browser-languagedetector'
|
||||
import XHR from 'i18next-xhr-backend'
|
||||
|
||||
import EnTranslations from './locales/en/translations.json'
|
||||
import FrTranslations from './locales/fr/translations.json'
|
||||
|
||||
i18n
|
||||
.use(XHR)
|
||||
.use(LanguageDetector)
|
||||
.init({
|
||||
debug: true,
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
keySeparator: false,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
resources: {
|
||||
en: {
|
||||
translations: EnTranslations,
|
||||
},
|
||||
fr: {
|
||||
translations: FrTranslations,
|
||||
},
|
||||
},
|
||||
ns: ['translations'],
|
||||
defaultNS: 'translations',
|
||||
})
|
||||
|
||||
export default i18n
|
@ -1,11 +1,13 @@
|
||||
/* eslint-disable react/jsx-filename-extension */
|
||||
import { createBrowserHistory } from 'history'
|
||||
import React from 'react'
|
||||
import { I18nextProvider } from 'react-i18next'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { routerMiddleware } from 'connected-react-router'
|
||||
import { applyMiddleware, createStore, compose } from 'redux'
|
||||
import { applyMiddleware, compose, createStore } from 'redux'
|
||||
import thunk from 'redux-thunk'
|
||||
|
||||
import i18n from './i18n'
|
||||
import App from './components/App'
|
||||
import Root from './components/Root'
|
||||
import registerServiceWorker from './registerServiceWorker'
|
||||
@ -34,7 +36,9 @@ if (window.localStorage.authToken !== null) {
|
||||
|
||||
ReactDOM.render(
|
||||
<Root store={store} history={history}>
|
||||
<App />
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<App />
|
||||
</I18nextProvider>
|
||||
</Root>,
|
||||
rootNode
|
||||
)
|
||||
|
15
fittrackee_client/src/locales/en/translations.json
Normal file
15
fittrackee_client/src/locales/en/translations.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"Dashboard": "Dashboard",
|
||||
"Workouts": "Workouts",
|
||||
"Statistics": "Statistics",
|
||||
"Add workout": "Add workout",
|
||||
"Register": "Register",
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"login": "login",
|
||||
"Enter a username": "Enter a username",
|
||||
"Enter an email address": "Enter an email address",
|
||||
"Enter a password": "Enter a password",
|
||||
"Enter the password confirmation": "Enter the password confirmation",
|
||||
"Submit": "Submit"
|
||||
}
|
15
fittrackee_client/src/locales/fr/translations.json
Normal file
15
fittrackee_client/src/locales/fr/translations.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"Dashboard": "Tableau de Bord",
|
||||
"Workouts": "Activités",
|
||||
"Statistics": "Statistiques",
|
||||
"Add workout": "Ajouter une activité",
|
||||
"Register": "S'inscrire",
|
||||
"Login": "Se connecter",
|
||||
"Logout": "Se déconnecter",
|
||||
"login": "se connecter",
|
||||
"Enter a username": "Saisir un nom",
|
||||
"Enter an email address": "Saisir une adresse e-mail",
|
||||
"Enter a password": "Saisir un mot de passe",
|
||||
"Enter the password confirmation": "Confirmer le mot de passe",
|
||||
"Submit": "Valider"
|
||||
}
|
Reference in New Issue
Block a user