Feature(langauge): Make client history language aware
Remove need for language aware links
This commit is contained in:
@ -10,6 +10,7 @@ import {
|
||||
} from 'react-router-redux';
|
||||
import { render } from 'redux-epic';
|
||||
import { createHistory } from 'history';
|
||||
import useLangRoutes from './use-lang-routes.js';
|
||||
|
||||
import createApp from '../common/app';
|
||||
import provideStore from '../common/app/provide-store';
|
||||
@ -36,7 +37,7 @@ initialState.app.csrfToken = csrfToken;
|
||||
|
||||
const serviceOptions = { xhrPath: '/services', context: { _csrf: csrfToken } };
|
||||
|
||||
const history = createHistory();
|
||||
const history = useLangRoutes(createHistory)();
|
||||
|
||||
const devTools = window.devToolsExtension ? window.devToolsExtension() : f => f;
|
||||
const adjustUrlOnReplay = !!window.devToolsExtension;
|
||||
|
44
client/use-lang-routes.js
Normal file
44
client/use-lang-routes.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { addLang, getLangFromPath } from '../common/app/utils/lang.js';
|
||||
|
||||
function addLangToLocation(location, lang) {
|
||||
if (!location) {
|
||||
return location;
|
||||
}
|
||||
if (typeof location === 'string') {
|
||||
return addLang(location, lang);
|
||||
}
|
||||
return {
|
||||
...location,
|
||||
pathname: addLang(location.pathname, lang)
|
||||
};
|
||||
}
|
||||
|
||||
function getLangFromLocation(location) {
|
||||
if (!location) {
|
||||
return location;
|
||||
}
|
||||
if (typeof location === 'string') {
|
||||
return getLangFromPath(location);
|
||||
}
|
||||
return getLangFromPath(location.pathname);
|
||||
}
|
||||
|
||||
export default function useLangRoutes(createHistory) {
|
||||
return (options = {}) => {
|
||||
let lang = 'en';
|
||||
const history = createHistory(options);
|
||||
const unsubscribeFromHistory = history.listen(nextLocation => {
|
||||
lang = getLangFromLocation(nextLocation);
|
||||
});
|
||||
const push = location => history.push(addLangToLocation(location, lang));
|
||||
const replace = location => history.replace(
|
||||
addLangToLocation(location, lang)
|
||||
);
|
||||
return {
|
||||
...history,
|
||||
push,
|
||||
replace,
|
||||
unsubscribe() { unsubscribeFromHistory(); }
|
||||
};
|
||||
};
|
||||
}
|
@ -36,15 +36,15 @@ const mapStateToProps = createSelector(
|
||||
isMapAlreadyLoaded,
|
||||
showChallengeComplete
|
||||
) => ({
|
||||
shouldShowSignIn,
|
||||
isSignedIn: !!username,
|
||||
username,
|
||||
points,
|
||||
picture,
|
||||
toast,
|
||||
shouldShowSignIn,
|
||||
isMapDrawerOpen,
|
||||
isMapAlreadyLoaded,
|
||||
showChallengeComplete
|
||||
showChallengeComplete,
|
||||
isSignedIn: !!username
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -5,6 +5,7 @@ const initialState = {
|
||||
title: 'Learn To Code | Free Code Camp',
|
||||
shouldShowSignIn: false,
|
||||
user: '',
|
||||
lang: '',
|
||||
csrfToken: '',
|
||||
windowHeight: 0,
|
||||
navHeight: 0,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import LangLink from '../../../../utils/Language-Link.jsx';
|
||||
import { Link } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
import FA from 'react-fontawesome';
|
||||
import PureComponent from 'react-pure-render/component';
|
||||
@ -61,7 +61,7 @@ export class Block extends PureComponent {
|
||||
className={ challengeClassName }
|
||||
key={ title }
|
||||
>
|
||||
<LangLink to={ `/challenges/${blockName}/${dashedName}` }>
|
||||
<Link to={ `/challenges/${blockName}/${dashedName}` }>
|
||||
<span
|
||||
onClick={ () => updateCurrentChallenge(challenge) }
|
||||
>
|
||||
@ -73,7 +73,7 @@ export class Block extends PureComponent {
|
||||
''
|
||||
}
|
||||
</span>
|
||||
</LangLink>
|
||||
</Link>
|
||||
</p>
|
||||
);
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { modernChallenges, map, challenges } from './challenges';
|
||||
import NotFound from '../components/NotFound/index.jsx';
|
||||
import { addLang } from '../utils/add-lang';
|
||||
import { addLang } from '../utils/lang';
|
||||
|
||||
export default {
|
||||
path: '/:lang',
|
||||
|
@ -1,30 +0,0 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link } from 'react-router';
|
||||
import { addLang } from './add-lang';
|
||||
|
||||
const mapStateToProps = state => ({ lang: state.app.lang });
|
||||
|
||||
export class LangLink extends React.Component {
|
||||
static displayName = 'LangLink';
|
||||
static propTypes = {
|
||||
to: PropTypes.string,
|
||||
lang: PropTypes.string
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
to,
|
||||
lang,
|
||||
...props
|
||||
} = this.props;
|
||||
return (
|
||||
<Link
|
||||
to={ addLang(to, lang) }
|
||||
{ ...props }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(LangLink);
|
@ -1,13 +0,0 @@
|
||||
import supportedLanguages from '../../utils/supported-languages';
|
||||
|
||||
const toLowerCase = String.prototype.toLowerCase;
|
||||
export function addLang(url, lang) {
|
||||
const maybeLang = toLowerCase.call(url.split('/')[1]);
|
||||
if (supportedLanguages[maybeLang]) {
|
||||
return url;
|
||||
}
|
||||
if (supportedLanguages[lang]) {
|
||||
return `/${lang}${url}`;
|
||||
}
|
||||
return `/en${url}`;
|
||||
}
|
39
common/app/utils/lang.js
Normal file
39
common/app/utils/lang.js
Normal file
@ -0,0 +1,39 @@
|
||||
import
|
||||
supportedLanguages,
|
||||
{ langTagRegex }
|
||||
from '../../utils/supported-languages';
|
||||
|
||||
const toLowerCase = String.prototype.toLowerCase;
|
||||
|
||||
export function getLangFromPath(path) {
|
||||
const maybeLang = toLowerCase.call(path.split('/')[1]);
|
||||
if (supportedLanguages[maybeLang]) {
|
||||
return maybeLang;
|
||||
}
|
||||
return 'en';
|
||||
}
|
||||
|
||||
export function addLang(path, lang, primaryLang) {
|
||||
// if maybeLang is supported continue
|
||||
// if maybeLang is unsupported lang, remove and use lang
|
||||
// if maybeLang is not lang tag, add lang tag.
|
||||
// if both primary and lang are not lang tags default en
|
||||
const maybeLang = toLowerCase.call(path.split('/')[1]);
|
||||
const restUrl = path.split('/').slice(2).join('/');
|
||||
|
||||
if (supportedLanguages[maybeLang]) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (
|
||||
langTagRegex.test(maybeLang) &&
|
||||
!supportedLanguages[maybeLang]
|
||||
) {
|
||||
return `/${primaryLang || lang }/${restUrl}`;
|
||||
}
|
||||
|
||||
if (supportedLanguages[primaryLang || lang]) {
|
||||
return `/${primaryLang || lang}${path}`;
|
||||
}
|
||||
return `/en${path}`;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
export const langTagRegex = /^[a-z]{2}(?:-[a-zA-Z]{2,3})?$/;
|
||||
export default {
|
||||
en: 'English',
|
||||
es: 'Spanish'
|
||||
|
@ -1,9 +1,11 @@
|
||||
import supportedLanguages from '../../common/utils/supported-languages';
|
||||
import
|
||||
supportedLanguages,
|
||||
{ langTagRegex }
|
||||
from '../../common/utils/supported-languages';
|
||||
import passthroughs from '../utils/lang-passthrough-urls';
|
||||
import debug from 'debug';
|
||||
|
||||
const log = debug('fcc:middlewares:lang');
|
||||
const langTagRegex = /^[a-z]{2}(?:-[a-zA-Z]{2,3})?$/;
|
||||
const toLowerCase = String.prototype.toLowerCase;
|
||||
|
||||
// redirect(statusOrUrl: String|Number, url?: String) => Void
|
||||
|
Reference in New Issue
Block a user