2017-10-15 22:00:21 +03:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2017-12-16 19:55:57 +03:00
|
|
|
import { TransitionMotion, spring, presets } from 'react-motion';
|
|
|
|
import { FormattedMessage as Message, intlShape } from 'react-intl';
|
2017-10-15 22:00:21 +03:00
|
|
|
|
|
|
|
import classNames from 'classnames';
|
|
|
|
|
|
|
|
import { requireLocaleFlag } from 'functions';
|
|
|
|
import LANGS from 'i18n/index.json';
|
|
|
|
|
|
|
|
import formStyles from 'components/ui/form/form.scss';
|
|
|
|
import popupStyles from 'components/ui/popup/popup.scss';
|
|
|
|
import icons from 'components/ui/icons.scss';
|
|
|
|
import styles from './languageSwitcher.scss';
|
|
|
|
import messages from './languageSwitcher.intl.json';
|
|
|
|
|
2017-12-16 03:36:39 +03:00
|
|
|
const improveTranslationUrl = 'http://ely.by/erickskrauch/posts/174943';
|
2017-12-16 19:55:57 +03:00
|
|
|
const itemHeight = 51;
|
2017-12-16 03:36:39 +03:00
|
|
|
|
2017-10-15 22:00:21 +03:00
|
|
|
class LanguageSwitcher extends Component {
|
|
|
|
static displayName = 'LanguageSwitcher';
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
onClose: PropTypes.func,
|
|
|
|
userLang: PropTypes.string,
|
|
|
|
changeLang: PropTypes.func,
|
2017-12-16 19:55:57 +03:00
|
|
|
langs: PropTypes.objectOf(PropTypes.object).isRequired,
|
2017-10-15 22:00:21 +03:00
|
|
|
};
|
|
|
|
|
2017-12-16 03:36:39 +03:00
|
|
|
static contextTypes = {
|
|
|
|
intl: intlShape.isRequired,
|
|
|
|
};
|
|
|
|
|
2017-10-15 22:00:21 +03:00
|
|
|
state = {
|
|
|
|
filter: '',
|
2017-12-16 19:55:57 +03:00
|
|
|
filteredLangs: this.props.langs,
|
2017-10-15 22:00:21 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static defaultProps = {
|
2017-12-16 19:55:57 +03:00
|
|
|
langs: LANGS,
|
|
|
|
onClose() {},
|
2017-10-15 22:00:21 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const {userLang, onClose} = this.props;
|
2017-12-16 19:55:57 +03:00
|
|
|
const firstLocale = Object.keys(this.state.filteredLangs)[0] || null;
|
2017-10-15 22:00:21 +03:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={styles.languageSwitcher}>
|
|
|
|
<div className={popupStyles.popup}>
|
|
|
|
<div className={popupStyles.header}>
|
|
|
|
<h2 className={popupStyles.headerTitle}>
|
|
|
|
<Message {...messages.siteLanguage} />
|
|
|
|
</h2>
|
|
|
|
<span className={classNames(icons.close, popupStyles.close)} onClick={onClose} />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className={styles.languageSwitcherBody}>
|
|
|
|
<div className={styles.searchBox}>
|
|
|
|
<input
|
|
|
|
className={classNames(
|
|
|
|
formStyles.lightTextField,
|
2017-12-16 19:55:57 +03:00
|
|
|
formStyles.greenTextField,
|
2017-10-15 22:00:21 +03:00
|
|
|
)}
|
2017-12-16 03:36:39 +03:00
|
|
|
placeholder={this.context.intl.formatMessage(messages.startTyping)}
|
2017-12-16 19:55:57 +03:00
|
|
|
onChange={this.onFilterUpdate}
|
2017-10-15 22:00:21 +03:00
|
|
|
onKeyPress={this.onFilterKeyPress()}
|
2017-12-16 03:36:39 +03:00
|
|
|
autoFocus
|
2017-10-15 22:00:21 +03:00
|
|
|
/>
|
|
|
|
<span className={styles.searchIcon} />
|
|
|
|
</div>
|
|
|
|
|
2017-12-16 19:55:57 +03:00
|
|
|
<TransitionMotion
|
|
|
|
defaultStyles={this.getItemsWithDefaultStyles()}
|
|
|
|
styles={this.getItemsWithStyles()}
|
|
|
|
willLeave={this.willLeave}
|
|
|
|
willEnter={this.willEnter}
|
|
|
|
>
|
|
|
|
{(items) => (
|
|
|
|
<div className={styles.languagesList}>
|
|
|
|
{items.map(({key: locale, data: definition, style}) => (
|
|
|
|
<li
|
|
|
|
key={locale}
|
|
|
|
style={style}
|
|
|
|
className={classNames(styles.languageItem, {
|
|
|
|
[styles.activeLanguageItem]: locale === userLang,
|
|
|
|
[styles.firstLanguageItem]: locale === firstLocale,
|
|
|
|
})}
|
|
|
|
onClick={this.onChangeLang(locale)}
|
|
|
|
>
|
|
|
|
{this.renderLanguageItem(locale, definition)}
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</TransitionMotion>
|
2017-10-15 22:00:21 +03:00
|
|
|
|
|
|
|
<div className={styles.improveTranslates}>
|
|
|
|
<div className={styles.improveTranslatesIcon} />
|
|
|
|
<div className={styles.improveTranslatesContent}>
|
|
|
|
<div className={styles.improveTranslatesTitle}>
|
|
|
|
<Message {...messages.improveTranslates} />
|
|
|
|
</div>
|
|
|
|
<div className={styles.improveTranslatesText}>
|
|
|
|
<Message {...messages.improveTranslatesDescription} values={{
|
|
|
|
articleLink: (
|
2017-12-16 03:36:39 +03:00
|
|
|
<a href={improveTranslationUrl} target="_blank">
|
2017-10-15 22:00:21 +03:00
|
|
|
<Message {...messages.improveTranslatesArticleLink} />
|
|
|
|
</a>
|
2017-12-16 19:55:57 +03:00
|
|
|
),
|
2017-10-15 22:00:21 +03:00
|
|
|
}} />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderLanguageItem(locale, localeData) {
|
|
|
|
const {name, progress, isReleased} = localeData;
|
|
|
|
let progressLabel;
|
|
|
|
if (progress !== 100) {
|
|
|
|
progressLabel = (
|
|
|
|
<Message {...messages.translationProgress} values={{
|
|
|
|
progress: `${progress}%`,
|
|
|
|
}} />
|
|
|
|
);
|
|
|
|
} else if (!isReleased) {
|
|
|
|
progressLabel = (
|
|
|
|
<Message {...messages.mayBeInaccurate} />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={styles.languageFlex}>
|
|
|
|
<div className={styles.languageIco} style={{
|
2017-12-16 19:55:57 +03:00
|
|
|
backgroundImage: `url('${requireLocaleFlag(locale)}')`,
|
2017-10-15 22:00:21 +03:00
|
|
|
}} />
|
|
|
|
<div className={styles.languageCaptions}>
|
|
|
|
<div className={styles.languageName}>
|
|
|
|
{name}
|
|
|
|
</div>
|
|
|
|
<div className={styles.languageSubName}>
|
|
|
|
{localeData.englishName} {progressLabel ? '| ' : ''} {progressLabel}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<span className={styles.languageCircle} />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
onChangeLang(lang) {
|
|
|
|
return (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
this.changeLang(lang);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
changeLang(lang) {
|
|
|
|
this.props.changeLang(lang);
|
|
|
|
setTimeout(this.props.onClose, 300);
|
|
|
|
}
|
|
|
|
|
2017-12-16 19:55:57 +03:00
|
|
|
onFilterUpdate = (event) => {
|
|
|
|
const filter = event.target.value.trim().toLowerCase();
|
|
|
|
const { langs } = this.props;
|
|
|
|
const result = Object.keys(langs).reduce((previous, key) => {
|
|
|
|
if (langs[key].englishName.toLowerCase().search(filter) === -1
|
|
|
|
&& langs[key].name.toLowerCase().search(filter) === -1
|
|
|
|
) {
|
|
|
|
return previous;
|
2017-10-15 22:00:21 +03:00
|
|
|
}
|
|
|
|
|
2017-12-16 19:55:57 +03:00
|
|
|
previous[key] = langs[key];
|
|
|
|
|
|
|
|
return previous;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
filter,
|
|
|
|
filteredLangs: result,
|
|
|
|
});
|
|
|
|
};
|
2017-10-15 22:00:21 +03:00
|
|
|
|
|
|
|
onFilterKeyPress() {
|
|
|
|
return (event) => {
|
|
|
|
if (event.key !== 'Enter' || this.state.filter === '') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-16 20:09:58 +03:00
|
|
|
const locales = Object.keys(this.state.filteredLangs);
|
2017-10-15 22:00:21 +03:00
|
|
|
if (locales.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.changeLang(locales[0]);
|
|
|
|
};
|
2017-12-16 03:36:39 +03:00
|
|
|
}
|
2017-12-16 19:55:57 +03:00
|
|
|
|
|
|
|
getItemsWithDefaultStyles = () => Object.keys(this.props.langs).reduce((previous, key) => {
|
|
|
|
return [
|
|
|
|
...previous,
|
|
|
|
{
|
|
|
|
key,
|
|
|
|
data: this.props.langs[key],
|
|
|
|
style: {
|
|
|
|
height: itemHeight,
|
|
|
|
opacity: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
getItemsWithStyles = () => Object.keys({...this.state.filteredLangs}).reduce((previous, key) => [
|
|
|
|
...previous,
|
|
|
|
{
|
|
|
|
key,
|
|
|
|
data: this.props.langs[key],
|
|
|
|
style: {
|
|
|
|
height: spring(itemHeight, presets.gentle),
|
|
|
|
opacity: spring(1, presets.gentle),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
], []);
|
|
|
|
|
|
|
|
willEnter() {
|
|
|
|
return {
|
|
|
|
height: 0,
|
|
|
|
opacity: 1,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
willLeave() {
|
|
|
|
return {
|
|
|
|
height: spring(0),
|
|
|
|
opacity: spring(0),
|
|
|
|
};
|
|
|
|
}
|
2017-10-15 22:00:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { changeLang } from 'components/user/actions';
|
|
|
|
|
|
|
|
export default connect((state) => ({
|
2017-12-16 19:55:57 +03:00
|
|
|
userLang: state.user.lang,
|
2017-10-15 22:00:21 +03:00
|
|
|
}), {
|
2017-12-16 19:55:57 +03:00
|
|
|
changeLang,
|
2017-10-15 22:00:21 +03:00
|
|
|
})(LanguageSwitcher);
|