From ddd5ddab2e5c6dd2dba4e5e602bbd8036a0eff89 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Sun, 15 Oct 2017 22:00:21 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BD?= =?UTF-8?q?=D0=B0=D1=8F=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=8F=D0=B7=D1=8B=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + scripts/i18n-onesky.js | 32 ++- src/components/footerMenu/FooterMenu.js | 23 +- .../footerMenu/footerMenu.intl.json | 3 +- src/components/footerMenu/footerMenu.scss | 13 ++ src/components/langMenu/LangMenu.js | 168 --------------- src/components/langMenu/index.js | 5 - src/components/langMenu/langMenu.intl.json | 4 - src/components/langMenu/langMenu.scss | 164 --------------- .../languageSwitcher/LanguageSwitcher.js | 197 ++++++++++++++++++ .../languageSwitcher.intl.json | 9 + .../languageSwitcher/languageSwitcher.scss | 162 ++++++++++++++ src/components/profile/Profile.js | 29 ++- src/components/profile/profile.scss | 22 ++ src/components/ui/form/form.scss | 5 - src/functions.js | 21 ++ src/i18n/index.json | 16 +- src/icons/flag_be.svg | 16 -- src/icons/flag_en.svg | 10 - src/icons/flag_fr.svg | 6 - src/icons/flag_id.svg | 5 - src/icons/flag_lt.svg | 6 - src/icons/flag_pl.svg | 5 - src/icons/flag_pt.svg | 90 -------- src/icons/flag_ro.svg | 6 - src/icons/flag_ru.svg | 1 - src/icons/flag_sl.svg | 23 -- src/icons/flag_uk.svg | 4 - src/icons/flag_vi.svg | 13 -- src/icons/webfont/search.svg | 9 + src/icons/webfont/translate.svg | 5 + 31 files changed, 527 insertions(+), 546 deletions(-) delete mode 100644 src/components/langMenu/index.js delete mode 100644 src/components/langMenu/langMenu.intl.json delete mode 100644 src/components/langMenu/langMenu.scss create mode 100644 src/components/languageSwitcher/LanguageSwitcher.js create mode 100644 src/components/languageSwitcher/languageSwitcher.intl.json create mode 100644 src/components/languageSwitcher/languageSwitcher.scss delete mode 100644 src/icons/flag_be.svg delete mode 100644 src/icons/flag_en.svg delete mode 100644 src/icons/flag_fr.svg delete mode 100644 src/icons/flag_id.svg delete mode 100644 src/icons/flag_lt.svg delete mode 100644 src/icons/flag_pl.svg delete mode 100644 src/icons/flag_pt.svg delete mode 100644 src/icons/flag_ro.svg delete mode 100644 src/icons/flag_ru.svg delete mode 100644 src/icons/flag_sl.svg delete mode 100644 src/icons/flag_uk.svg delete mode 100644 src/icons/flag_vi.svg create mode 100644 src/icons/webfont/search.svg create mode 100644 src/icons/webfont/translate.svg diff --git a/package.json b/package.json index f65418b..a0588eb 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "babel-polyfill": "^6.3.14", "classnames": "^2.1.3", "debounce": "^1.0.0", + "flag-icon-css": "^2.8.0", "intl": "^1.2.2", "intl-format-cache": "^2.0.4", "intl-messageformat": "^2.1.0", diff --git a/scripts/i18n-onesky.js b/scripts/i18n-onesky.js index 4e8b80f..cf6847d 100644 --- a/scripts/i18n-onesky.js +++ b/scripts/i18n-onesky.js @@ -26,6 +26,24 @@ const LOCALES_MAP = { lt: 'lt-LT', }; +/** + * Некоторые языки, после выгрузки из OneSky, имеют не очень информативные названия, + * так что здесь можно указать точные имена для результирующего файла index.json + */ +const ORIGINAL_NAMES_MAP = { + en: 'English, UK', + pt: 'Português do Brasil', +}; + +/** + * Некоторые языки, после выгрузки из OneSky, имеют не очень точные английские названия, + * так что здесь можно указать точные имена для результирующего файла index.json + */ +const ENGLISH_NAMES_MAP = { + en: 'English, UK', + pt: 'Portuguese, Brazilian', +}; + // https://ely-translates.oneskyapp.com/admin/site/settings const defaultOptions = { apiKey: '5MaW9TYp0S3qdJgkZ5QLgEIDeabkFDzB', @@ -83,6 +101,17 @@ function sortByKeys(object) { }, {}); } +/** + * Убирает значение в скобках. + * Например: "French (France)" => "French". + * + * @param {string} value + * @return {string} + */ +function trimValueInBrackets(value) { + return value.match(/^([^\(]+)/)[0].trim(); +} + async function pullReadyLanguages() { const languages = JSON.parse(await onesky.getLanguages({...defaultOptions})); return languages.data @@ -112,7 +141,8 @@ async function pull() { const mapFileContent = {}; langs.map((elem) => { mapFileContent[elem.locale] = { - name: elem.local_name.match(/^([^\(]+)/)[0].trim(), // Обрезаем значения в скобках + name: ORIGINAL_NAMES_MAP[elem.locale] || trimValueInBrackets(elem.local_name), + englishName: ENGLISH_NAMES_MAP[elem.locale] || trimValueInBrackets(elem.english_name), progress: parseFloat(elem.translation_progress), isReleased: elem.is_ready_to_publish, }; diff --git a/src/components/footerMenu/FooterMenu.js b/src/components/footerMenu/FooterMenu.js index f419ac2..9a3bfa2 100644 --- a/src/components/footerMenu/FooterMenu.js +++ b/src/components/footerMenu/FooterMenu.js @@ -4,8 +4,6 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage as Message } from 'react-intl'; -import { LangMenu } from 'components/langMenu'; - import styles from './footerMenu.scss'; import messages from './footerMenu.intl.json'; @@ -13,7 +11,8 @@ class FooterMenu extends Component { static displayName = 'FooterMenu'; static propTypes = { - createPopup: PropTypes.func.isRequired + createContactPopup: PropTypes.func.isRequired, + createLanguageSwitcherPopup: PropTypes.func.isRequired, }; render() { @@ -27,23 +26,35 @@ class FooterMenu extends Component { - +
+ + + + +
); } onContact = (event) => { event.preventDefault(); - this.props.createPopup(); + this.props.createContactPopup(); + }; + + onLanguageSwitcher = (event) => { + event.preventDefault(); + this.props.createLanguageSwitcherPopup(); }; } import { connect } from 'react-redux'; import ContactForm from 'components/contact/ContactForm'; +import LanguageSwitcher from 'components/languageSwitcher/LanguageSwitcher'; import { create as createPopup } from 'components/ui/popup/actions'; // mark this component, as not pure, because it is stateless, // but should be re-rendered, if current lang was changed export default connect(null, { - createPopup: () => createPopup(ContactForm) + createContactPopup: () => createPopup(ContactForm), + createLanguageSwitcherPopup: () => createPopup(LanguageSwitcher), }, null, {pure: false})(FooterMenu); diff --git a/src/components/footerMenu/footerMenu.intl.json b/src/components/footerMenu/footerMenu.intl.json index be3af35..3f1edef 100644 --- a/src/components/footerMenu/footerMenu.intl.json +++ b/src/components/footerMenu/footerMenu.intl.json @@ -1,4 +1,5 @@ { "rules": "Rules", - "contactUs": "Contact Us" + "contactUs": "Contact Us", + "siteLanguage": "Site language" } diff --git a/src/components/footerMenu/footerMenu.scss b/src/components/footerMenu/footerMenu.scss index e67d34d..734918c 100644 --- a/src/components/footerMenu/footerMenu.scss +++ b/src/components/footerMenu/footerMenu.scss @@ -8,3 +8,16 @@ border-bottom-color: #666; } } + +.langTriggerContainer { + text-align: center; +} + +.langTriggerIcon { + composes: globe from 'components/ui/icons.scss'; + + position: relative; + bottom: 1px; + font-size: 11px; + margin-right: 3px; +} diff --git a/src/components/langMenu/LangMenu.js b/src/components/langMenu/LangMenu.js index 1a867a2..e69de29 100644 --- a/src/components/langMenu/LangMenu.js +++ b/src/components/langMenu/LangMenu.js @@ -1,168 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; - -import classNames from 'classnames'; -import { FormattedMessage as Message } from 'react-intl'; - -import styles from './langMenu.scss'; -import messages from './langMenu.intl.json'; - -import LANGS from 'i18n/index.json'; - -class LangMenu extends Component { - static propTypes = { - showCurrentLang: PropTypes.bool, - toggleRef: PropTypes.func, - userLang: PropTypes.string, - changeLang: PropTypes.func - }; - static defaultProps = { - toggleRef: () => {}, - showCurrentLang: false - }; - - state = { - isActive: false - }; - - componentDidMount() { - document.addEventListener('click', this.onBodyClick); - this.props.toggleRef(this.toggle.bind(this)); - } - - componentWillUnmount() { - document.removeEventListener('click', this.onBodyClick); - this.props.toggleRef(null); - } - - render() { - const {userLang: userLocale, showCurrentLang} = this.props; - const {isActive} = this.state; - - return ( -
-
-
    - {Object.keys(LANGS).map((locale) => ( -
  • - {this.renderLangLabel(locale, LANGS[locale])} -
  • - ))} -
  • - - - -
  • -
-
- -
- - {showCurrentLang - ? this.renderLangLabel(userLocale, LANGS[userLocale]) : ( - - - {' '} - - {' '} - - - )} - -
-
- ); - } - - renderLangLabel(locale, localeData) { - const {name, progress, isReleased} = localeData; - let progressLabel; - - if (progress !== 100) { - progressLabel = ( - - {`(${progress}%)`} - - ); - } else if (!isReleased) { - progressLabel = ( - - {'*'} - - ); - } - - return ( - - - {this.formatLocaleName(locale) || name} - {progressLabel} - - ); - } - - formatLocaleName(locale) { - switch (locale) { - case 'pt': - return 'Português (Br)'; - default: - return null; - } - } - - onChangeLang(lang) { - return (event) => { - event.preventDefault(); - - this.props.changeLang(lang); - this.setState({ - isActive: false - }); - }; - } - - onBodyClick = (event) => { - if (this.state.isActive) { - const el = ReactDOM.findDOMNode(this); - - if (!el.contains(event.target) && el !== event.taget) { - event.preventDefault(); - - // add a small delay for the case someone have alredy called toggle - setTimeout(() => this.state.isActive && this.toggle(), 0); - } - } - }; - - onToggle = (event) => { - event.preventDefault(); - - this.toggle(); - }; - - toggle = () => { - // add small delay to skip click event on body - setTimeout(() => this.setState({ - isActive: !this.state.isActive - }), 0); - }; -} - -import { connect } from 'react-redux'; -import { changeLang } from 'components/user/actions'; - -export default connect((state) => ({ - userLang: state.user.lang -}), { - changeLang -})(LangMenu); diff --git a/src/components/langMenu/index.js b/src/components/langMenu/index.js deleted file mode 100644 index 33b1b7b..0000000 --- a/src/components/langMenu/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import LangMenu from './LangMenu'; - -export { - LangMenu -}; diff --git a/src/components/langMenu/langMenu.intl.json b/src/components/langMenu/langMenu.intl.json deleted file mode 100644 index ec2bab4..0000000 --- a/src/components/langMenu/langMenu.intl.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "siteLanguage": "Site language", - "improveTranslations": "Improve translations" -} diff --git a/src/components/langMenu/langMenu.scss b/src/components/langMenu/langMenu.scss deleted file mode 100644 index eb79aef..0000000 --- a/src/components/langMenu/langMenu.scss +++ /dev/null @@ -1,164 +0,0 @@ -@import "~components/ui/colors.scss"; -@import "~components/ui/fonts.scss"; - -.container { - position: relative; -} - -.menuContainer { - position: absolute; - bottom: 100%; - left: 0; - right: 0; - - display: inline-flex; - justify-content: center; - margin: 0 auto 10px; - - perspective: 600px; - pointer-events: none; -} - -.menu { - pointer-events: auto; - background: #fff; - border: 5px solid #ddd8ce; - border-left: 0; - border-right: 0; - text-align: left; - box-shadow: 0 0 1px rgba(#000, .2); - - visibility: hidden; - opacity: 0; - transition: .3s cubic-bezier(0.075, 0.82, 0.165, 1); // easeOutCirc - transform: translateY(10px) rotateX(-17deg); -} - -.menuActive { - visibility: visible; - opacity: 1; - transform: translateY(0) rotateX(0deg); -} - -.withCurrentLang { - .triggerContainer { - text-align: left; - } - - .menuContainer { - justify-content: flex-start; - } -} - -.menuItem { - position: relative; - padding: 10px; - font-size: 13px; - border-bottom: 1px solid #eee; - cursor: pointer; - transition: .2s; - - &:hover { - background: $whiteButtonLight; - color: #262626; - } - - &:last-child { - border-bottom: none; - } -} - -.activeMenuItem { - background: lighter($green)!important; - color: #fff!important; - font-weight: $font-weight-bold; -} - -.langIco { - position: relative; - display: inline-block; - margin-right: 5px; - width: 20px; - height: 10px; - box-shadow: 0 0 1px rgba(#000, .2); - - background: no-repeat; - background-size: cover; -} - -.langTranslateProgress { - font-size: 9px; - position: relative; - font-family: $font-family-base; - color: #ccc; -} - -.langTranslateUnfinished { - composes: langTranslateProgress; - - top: -1px; - padding-left: 3px; -} - -.langTranslateUnreviewed { - composes: langTranslateProgress; - - top: -4px; -} - -.improveTranslatesLink { - font-size: 11px; - text-align: center; - padding: 5px 10px; - - a { - color: #9a9a9a; - border-bottom-color: #9a9a9a; - } -} - -.trigger { - color: #666; - border-bottom: 1px dotted #666; - text-decoration: none; - transition: .25s; - - &:hover { - border-bottom-color: #777; - color: #777; - } -} - -.triggerContainer { - text-align: center; -} - -.trigger { - font-size: 12px; -} - -.triggerIcon { - composes: globe from 'components/ui/icons.scss'; - - position: relative; - bottom: 1px; - font-size: 11px; -} - -.triggerArrow { - font-size: 8px; - transition: 0.2s; -} - -.triggerArrowTop { - composes: triggerArrow; - composes: arrowTop from 'components/ui/icons.scss'; -} - -.triggerArrowBottom { - composes: triggerArrow; - composes: arrowBottom from 'components/ui/icons.scss'; - - // Докручиваем лишний раз, чтобы иконка крутилась по часовой стрелке - transform: rotate(360deg); -} diff --git a/src/components/languageSwitcher/LanguageSwitcher.js b/src/components/languageSwitcher/LanguageSwitcher.js new file mode 100644 index 0000000..9a0a15f --- /dev/null +++ b/src/components/languageSwitcher/LanguageSwitcher.js @@ -0,0 +1,197 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; +import { FormattedMessage as Message } from 'react-intl'; + +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'; + +class LanguageSwitcher extends Component { + static displayName = 'LanguageSwitcher'; + + static propTypes = { + onClose: PropTypes.func, + userLang: PropTypes.string, + changeLang: PropTypes.func, + }; + + state = { + items: [], + filter: '', + }; + + static defaultProps = { + onClose() {} + }; + + componentWillMount() { + this.setState({items: LANGS}); + } + + render() { + const {userLang, onClose} = this.props; + const {items} = this.state; + + return ( +
+
+
+

+ +

+ +
+ +
+
+ + {(placeholder) => ( + {placeholder} + )} + + } + onChange={this.onFilterUpdate()} + onKeyPress={this.onFilterKeyPress()} + /> + +
+ +
+ {Object.keys(items).map((locale) => ( +
  • + {this.renderLanguageItem(locale, items[locale])} +
  • + ))} +
    + +
    +
    +
    +
    + +
    +
    + + + + ) + }} /> +
    +
    +
    +
    +
    +
    + ); + } + + renderLanguageItem(locale, localeData) { + const {name, progress, isReleased} = localeData; + let progressLabel; + if (progress !== 100) { + progressLabel = ( + + ); + } else if (!isReleased) { + progressLabel = ( + + ); + } + + return ( +
    +
    +
    +
    + {name} +
    +
    + {localeData.englishName} {progressLabel ? '| ' : ''} {progressLabel} +
    +
    + +
    + ); + } + + onChangeLang(lang) { + return (event) => { + event.preventDefault(); + this.changeLang(lang); + }; + } + + changeLang(lang) { + this.props.changeLang(lang); + setTimeout(this.props.onClose, 300); + } + + onFilterUpdate() { + return (event) => { + const value = event.target.value.trim().toLowerCase(); + let items = LANGS; + if (value.length !== 0) { + items = Object.keys(items).reduce((prev, next) => { + if (items[next].englishName.toLowerCase().search(value) !== -1 + || items[next].name.toLowerCase().search(value) !== -1 + ) { + prev[next] = items[next]; + } + + return prev; + }, {}); + } + + this.setState({ + items, + filter: value, + }); + }; + } + + onFilterKeyPress() { + return (event) => { + if (event.key !== 'Enter' || this.state.filter === '') { + return; + } + + const locales = Object.keys(this.state.items); + if (locales.length === 0) { + return; + } + + this.changeLang(locales[0]); + }; + }; +} + +import { connect } from 'react-redux'; +import { changeLang } from 'components/user/actions'; + +export default connect((state) => ({ + userLang: state.user.lang +}), { + changeLang +})(LanguageSwitcher); diff --git a/src/components/languageSwitcher/languageSwitcher.intl.json b/src/components/languageSwitcher/languageSwitcher.intl.json new file mode 100644 index 0000000..c85edf8 --- /dev/null +++ b/src/components/languageSwitcher/languageSwitcher.intl.json @@ -0,0 +1,9 @@ +{ + "siteLanguage": "Site language", + "startTyping": "Start typing…", + "translationProgress": "{progress} translated", + "mayBeInaccurate": "May be inaccurate", + "improveTranslates": "Improve Ely.by translation", + "improveTranslatesDescription": "Ely.by’s localization is a community effort. If you want to see Ely.by translated into another language, we'd love your help. To apply read {articleLink}.", + "improveTranslatesArticleLink": "this article" +} diff --git a/src/components/languageSwitcher/languageSwitcher.scss b/src/components/languageSwitcher/languageSwitcher.scss new file mode 100644 index 0000000..b36e093 --- /dev/null +++ b/src/components/languageSwitcher/languageSwitcher.scss @@ -0,0 +1,162 @@ +@import '~components/ui/colors.scss'; +@import '~components/ui/fonts.scss'; +@import '~components/ui/popup/popup.scss'; + +.languageSwitcher { + composes: popupWrapper from 'components/ui/popup/popup.scss'; + + @include popupBounding(400px); +} + +.languageSwitcherBody { + composes: body from 'components/ui/popup/popup.scss'; + + display: flex; + flex-direction: column; + max-height: 550px; +} + +.searchBox { + position: relative; + margin-bottom: 20px; +} + +.searchIcon { + composes: search from 'components/ui/icons.scss'; + + position: absolute; + top: 14px; + right: 12px; + font-size: 22px; + color: #EDEBE5; + pointer-events: none; // Иконка чисто декоративная, так что клик должен проходить сквозь неё +} + +$languageListBorderStyle: 1px solid #eee; + +.languagesList { + flex-grow: 1; + overflow-y: auto; + border-top: $languageListBorderStyle; + border-bottom: $languageListBorderStyle; + margin-bottom: 20px; +} + +.languageItem { + padding: 10px; + border-top: $languageListBorderStyle; + font-family: $font-family-title; + transition: .25s; + cursor: pointer; + overflow: hidden; + + &:first-child { + border-top: none; + } + + &:hover { + background: $whiteButtonLight; + } +} + +.languageFlex { + display: flex; + align-items: center; +} + +.languageIco { + display: inline-block; + margin-right: 7px; + width: 40px; + height: 30px; + box-shadow: 0 0 1px rgba(#000, .2); + + background: no-repeat; + background-size: cover; +} + +.languageCaptions { + flex-grow: 1; +} + +.languageName { + font-size: 15px; + margin-bottom: 2px; +} + +.languageSubName { + font-size: 11px; + color: #CCC; +} + +// Реализация радио кнопки. Когда у нас будет нормальный компонент радио кнопок, нужно будет перейти на него +.languageCircle { + composes: checkmark from 'components/ui/icons.scss'; + + position: relative; + box-sizing: border-box; + width: 22px; + height: 22px; + right: -32px; + + + font-size: 10px; + line-height: 18px; + text-align: center; + color: #fff; + border: 2px solid #DCD8CD; + border-radius: 50%; + + transition: .5s cubic-bezier(0.19, 1, 0.22, 1); + + &:before { + opacity: 0; + transition: opacity 0.3s; + } + + .languageItem:hover & { + right: 0; + } + + .activeLanguageItem & { + border-color: $green; + background: $green; + right: 0; + + &:before { + opacity: 1; + } + } +} + +.improveTranslates { + border: 1px solid #DEDEDE; + background: #F3F1ED; + padding: 10px; + display: flex; + flex-shrink: 0; +} + +.improveTranslatesIcon { + composes: translate from 'components/ui/icons.scss'; + + color: lighter($blue); + font-size: 22px; + margin-right: 10px; +} + +.improveTranslatesContent { + +} + +.improveTranslatesTitle { + font-family: $font-family-title; + font-size: 13px; + margin-bottom: 3px; +} + +.improveTranslatesText { + font-size: 10px; + color: #9A9A9A; + line-height: 1.2; +} diff --git a/src/components/profile/Profile.js b/src/components/profile/Profile.js index 3044516..da82988 100644 --- a/src/components/profile/Profile.js +++ b/src/components/profile/Profile.js @@ -1,11 +1,14 @@ import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import { FormattedMessage as Message, FormattedRelative as Relative } from 'react-intl'; import { Link } from 'react-router-dom'; import Helmet from 'react-helmet'; +import { requireLocaleFlag } from 'functions'; +import LANGS from 'i18n/index.json'; + import { userShape } from 'components/user/User'; -import { LangMenu } from 'components/langMenu'; import ProfileField from './ProfileField'; import styles from './profile.scss'; @@ -17,7 +20,8 @@ import RulesPage from 'pages/rules/RulesPage'; class Profile extends Component { static displayName = 'Profile'; static propTypes = { - user: userShape + user: userShape, + createLanguageSwitcherPopup: PropTypes.func.isRequired, }; render() { @@ -86,7 +90,14 @@ class Profile extends Component { } - value={} + value={ + + + {LANGS[user.lang].name} + + } /> ({ - user: state.user -}))(Profile); + user: state.user, +}), { + createLanguageSwitcherPopup: () => createPopup(LanguageSwitcher), +})(Profile); diff --git a/src/components/profile/profile.scss b/src/components/profile/profile.scss index cfb856a..f66ebfe 100644 --- a/src/components/profile/profile.scss +++ b/src/components/profile/profile.scss @@ -68,6 +68,28 @@ $formColumnWidth: 416px; flex-grow: 1; } +.language { + color: #666; + border-bottom: 1px dotted #666; + text-decoration: none; + transition: .25s; + cursor: pointer; +} + +.languageIcon { + $height: 13px; + + position: relative; + top: 1px; + display: inline-block; + margin-right: 4px; + height: $height; + width: $height * 4 / 3; + box-shadow: 0 0 1px rgba(#000, .2); + + background-size: cover; +} + .uuidValue { composes: paramName; composes: paramValue; diff --git a/src/components/ui/form/form.scss b/src/components/ui/form/form.scss index 41a3b21..6f8f522 100644 --- a/src/components/ui/form/form.scss +++ b/src/components/ui/form/form.scss @@ -49,11 +49,6 @@ .textField { box-sizing: border-box; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; height: 50px; width: 100%; diff --git a/src/functions.js b/src/functions.js index 0c37edf..88fef99 100644 --- a/src/functions.js +++ b/src/functions.js @@ -79,3 +79,24 @@ export function getJwtPayload(jwt: string): Object { throw new Error('Can not decode jwt token'); } } + +const localeToCountryCode = { + en: 'gb', + be: 'by', + pt: 'br', + uk: 'ua', + vi: 'vn', + sl: 'si', +}; + +/** + * Возвращает для указанной локали её флаг с учётом всех нюансов загрузки флага + * и подбора соответствующего локали флага. + * + * @param {string} locale + * @return {*} + */ +export function requireLocaleFlag(locale: string) { + return require(`flag-icon-css/flags/4x3/${localeToCountryCode[locale] || locale}.svg`); +} + diff --git a/src/i18n/index.json b/src/i18n/index.json index f5d71a6..8295f3a 100644 --- a/src/i18n/index.json +++ b/src/i18n/index.json @@ -1,61 +1,73 @@ { "be": { "name": "Беларуская", + "englishName": "Belarusian", "progress": 100, "isReleased": true }, "en": { - "name": "English", + "name": "English, UK", + "englishName": "English, UK", "progress": 100, "isReleased": true }, "fr": { "name": "Français", + "englishName": "French", "progress": 89, "isReleased": true }, "id": { "name": "Bahasa Indonesia", + "englishName": "Indonesian", "progress": 100, "isReleased": true }, "lt": { "name": "Lietuvių", + "englishName": "Lithuanian", "progress": 96.9, "isReleased": false }, "pl": { "name": "Polski", + "englishName": "Polish", "progress": 85.5, "isReleased": false }, "pt": { - "name": "Português", + "name": "Português do Brasil", + "englishName": "Portuguese, Brazilian", "progress": 100, "isReleased": true }, "ro": { "name": "Română", + "englishName": "Romanian", "progress": 85.5, "isReleased": false }, "ru": { "name": "Русский", + "englishName": "Russian", "progress": 100, "isReleased": true }, "sl": { "name": "Slovenščina", + "englishName": "Slovenian", "progress": 86, "isReleased": false }, "uk": { "name": "Українська", + "englishName": "Ukrainian", "progress": 89, "isReleased": true }, "vi": { "name": "Tiếng Việt", + "englishName": "Vietnamese", "progress": 96.9, "isReleased": true } diff --git a/src/icons/flag_be.svg b/src/icons/flag_be.svg deleted file mode 100644 index 05ba5e8..0000000 --- a/src/icons/flag_be.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - -Flag of Belarus - - - - - - - - - - - - diff --git a/src/icons/flag_en.svg b/src/icons/flag_en.svg deleted file mode 100644 index 36c9889..0000000 --- a/src/icons/flag_en.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/icons/flag_fr.svg b/src/icons/flag_fr.svg deleted file mode 100644 index c605a12..0000000 --- a/src/icons/flag_fr.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/icons/flag_id.svg b/src/icons/flag_id.svg deleted file mode 100644 index 9bce03b..0000000 --- a/src/icons/flag_id.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/icons/flag_lt.svg b/src/icons/flag_lt.svg deleted file mode 100644 index 287a21a..0000000 --- a/src/icons/flag_lt.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/icons/flag_pl.svg b/src/icons/flag_pl.svg deleted file mode 100644 index c9e1be3..0000000 --- a/src/icons/flag_pl.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/icons/flag_pt.svg b/src/icons/flag_pt.svg deleted file mode 100644 index 88b9522..0000000 --- a/src/icons/flag_pt.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/icons/flag_ro.svg b/src/icons/flag_ro.svg deleted file mode 100644 index b19eae4..0000000 --- a/src/icons/flag_ro.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/icons/flag_ru.svg b/src/icons/flag_ru.svg deleted file mode 100644 index b6f43d1..0000000 --- a/src/icons/flag_ru.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/icons/flag_sl.svg b/src/icons/flag_sl.svg deleted file mode 100644 index df9fc1d..0000000 --- a/src/icons/flag_sl.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/icons/flag_uk.svg b/src/icons/flag_uk.svg deleted file mode 100644 index 551b203..0000000 --- a/src/icons/flag_uk.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/icons/flag_vi.svg b/src/icons/flag_vi.svg deleted file mode 100644 index 7bb5f6e..0000000 --- a/src/icons/flag_vi.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/icons/webfont/search.svg b/src/icons/webfont/search.svg new file mode 100644 index 0000000..b4eaa8d --- /dev/null +++ b/src/icons/webfont/search.svg @@ -0,0 +1,9 @@ + + + + diff --git a/src/icons/webfont/translate.svg b/src/icons/webfont/translate.svg new file mode 100644 index 0000000..3acadc0 --- /dev/null +++ b/src/icons/webfont/translate.svg @@ -0,0 +1,5 @@ + + +translate + +