- client: Make language tag in HTML same as setting language

Close #1797

Squashed commit of the following:

commit b822a83cb05cc5ba92000cdb7d1c12629471bc57
Merge: e2fa24fb 72ce5f57
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Fri Jul 3 11:02:56 2020 +0300

    Merge branch 'master' into fix/1797

commit e2fa24fb9fa0c15f8411e186e90e0ffb1c705fb2
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Jul 2 18:21:30 2020 +0300

    Extract helper

commit ba8473e7b16ab8b1abbee4b42a4ef2b0de8c136b
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Jul 2 15:31:42 2020 +0300

    - client: Make language tag in HTML same as setting language
This commit is contained in:
Artem Baskal 2020-07-03 11:14:54 +03:00
parent 72ce5f57c1
commit 205680b71b
5 changed files with 106 additions and 75 deletions

View File

@ -70,9 +70,18 @@ export const initSettings = (settingsList) => async (dispatch) => {
safesearch, safesearch,
} = settingsList; } = settingsList;
const newSettingsList = { const newSettingsList = {
safebrowsing: { ...safebrowsing, enabled: safebrowsingStatus.enabled }, safebrowsing: {
parental: { ...parental, enabled: parentalStatus.enabled }, ...safebrowsing,
safesearch: { ...safesearch, enabled: safesearchStatus.enabled }, enabled: safebrowsingStatus.enabled,
},
parental: {
...parental,
enabled: parentalStatus.enabled,
},
safesearch: {
...safesearch,
enabled: safesearchStatus.enabled,
},
}; };
dispatch(initSettingsSuccess({ settingsList: newSettingsList })); dispatch(initSettingsSuccess({ settingsList: newSettingsList }));
} catch (error) { } catch (error) {
@ -274,13 +283,14 @@ export const testUpstream = (config) => async (dispatch) => {
values.upstream_dns = normalizeTextarea(values.upstream_dns); values.upstream_dns = normalizeTextarea(values.upstream_dns);
const upstreamResponse = await apiClient.testUpstream(values); const upstreamResponse = await apiClient.testUpstream(values);
const testMessages = Object.keys(upstreamResponse).map((key) => { const testMessages = Object.keys(upstreamResponse)
const message = upstreamResponse[key]; .map((key) => {
if (message !== 'OK') { const message = upstreamResponse[key];
dispatch(addErrorToast({ error: i18next.t('dns_test_not_ok_toast', { key }) })); if (message !== 'OK') {
} dispatch(addErrorToast({ error: i18next.t('dns_test_not_ok_toast', { key }) }));
return message; }
}); return message;
});
if (testMessages.every((message) => message === 'OK')) { if (testMessages.every((message) => message === 'OK')) {
dispatch(addSuccessToast('dns_test_ok_toast')); dispatch(addSuccessToast('dns_test_ok_toast'));
@ -393,11 +403,17 @@ export const toggleDhcpSuccess = createAction('TOGGLE_DHCP_SUCCESS');
export const toggleDhcp = (values) => async (dispatch) => { export const toggleDhcp = (values) => async (dispatch) => {
dispatch(toggleDhcpRequest()); dispatch(toggleDhcpRequest());
let config = { ...values, enabled: false }; let config = {
...values,
enabled: false,
};
let successMessage = 'disabled_dhcp'; let successMessage = 'disabled_dhcp';
if (!values.enabled) { if (!values.enabled) {
config = { ...values, enabled: true }; config = {
...values,
enabled: true,
};
successMessage = 'enabled_dhcp'; successMessage = 'enabled_dhcp';
dispatch(findActiveDhcp(values.interface_name)); dispatch(findActiveDhcp(values.interface_name));
} }

View File

@ -36,6 +36,7 @@ import i18n from '../../i18n';
import Loading from '../ui/Loading'; import Loading from '../ui/Loading';
import { FILTERS_URLS, MENU_URLS, SETTINGS_URLS } from '../../helpers/constants'; import { FILTERS_URLS, MENU_URLS, SETTINGS_URLS } from '../../helpers/constants';
import Services from '../Filters/Services'; import Services from '../Filters/Services';
import { setHtmlLangAttr } from '../../helpers/helpers';
class App extends Component { class App extends Component {
componentDidMount() { componentDidMount() {
@ -62,6 +63,7 @@ class App extends Component {
if (!processing) { if (!processing) {
if (language) { if (language) {
i18n.changeLanguage(language); i18n.changeLanguage(language);
setHtmlLangAttr(language);
} }
} }

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import classNames from 'classnames'; import classNames from 'classnames';
import { REPOSITORY, PRIVACY_POLICY_LINK } from '../../helpers/constants'; import { REPOSITORY, PRIVACY_POLICY_LINK } from '../../helpers/constants';
@ -10,6 +10,7 @@ import i18n from '../../i18n';
import Version from './Version'; import Version from './Version';
import './Footer.css'; import './Footer.css';
import './Select.css'; import './Select.css';
import { setHtmlLangAttr } from '../../helpers/helpers';
const linksData = [ const linksData = [
{ {
@ -27,83 +28,85 @@ const linksData = [
}, },
]; ];
class Footer extends Component { const Footer = (props) => {
getYear = () => { const { t } = useTranslation();
const getYear = () => {
const today = new Date(); const today = new Date();
return today.getFullYear(); return today.getFullYear();
}; };
changeLanguage = (event) => { const changeLanguage = (event) => {
i18n.changeLanguage(event.target.value); const { value } = event.target;
i18n.changeLanguage(value);
setHtmlLangAttr(value);
}; };
renderCopyright = () => <div className="footer__column"> const renderCopyright = () => <div className="footer__column">
<div className="footer__copyright"> <div className="footer__copyright">
<Trans>copyright</Trans> &copy; {this.getYear()}{' '} {t('copyright')} &copy; {getYear()}{' '}
<a target="_blank" rel="noopener noreferrer" href="https://adguard.com/">AdGuard</a> <a target="_blank" rel="noopener noreferrer" href="https://adguard.com/">AdGuard</a>
</div> </div>
</div>; </div>;
renderLinks = (linksData) => linksData.map(({ name, href, className = '' }) => <a const renderLinks = (linksData) => linksData.map(({ name, href, className = '' }) => <a
key={name} key={name}
href={href} href={href}
className={classNames('footer__link', className)} className={classNames('footer__link', className)}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
<Trans>{name}</Trans> {t(name)}
</a>); </a>);
render() { const {
const { dnsVersion, processingVersion, getVersion, checkUpdateFlag,
dnsVersion, processingVersion, getVersion, checkUpdateFlag, } = props;
} = this.props;
return ( return (
<Fragment> <>
<footer className="footer"> <footer className="footer">
<div className="container"> <div className="container">
<div className="footer__row"> <div className="footer__row">
<div className="footer__column footer__column--links"> <div className="footer__column footer__column--links">
{this.renderLinks(linksData)} {renderLinks(linksData)}
</div>
<div className="footer__column footer__column--language">
<select
className="form-control select select--language"
value={i18n.language}
onChange={this.changeLanguage}
>
{Object.keys(LANGUAGES)
.map((lang) => (
<option key={lang} value={lang}>
{LANGUAGES[lang]}
</option>
))}
</select>
</div>
</div> </div>
</div> <div className="footer__column footer__column--language">
</footer> <select
<div className="footer"> className="form-control select select--language"
<div className="container"> value={i18n.language}
<div className="footer__row"> onChange={changeLanguage}
{this.renderCopyright()} >
<div className="footer__column footer__column--language"> {Object.keys(LANGUAGES)
<Version .map((lang) => (
dnsVersion={dnsVersion} <option key={lang} value={lang}>
processingVersion={processingVersion} {LANGUAGES[lang]}
getVersion={getVersion} </option>
checkUpdateFlag={checkUpdateFlag} ))}
/> </select>
</div>
</div> </div>
</div> </div>
</div> </div>
</Fragment> </footer>
); <div className="footer">
} <div className="container">
} <div className="footer__row">
{renderCopyright()}
<div className="footer__column footer__column--language">
<Version
dnsVersion={dnsVersion}
processingVersion={processingVersion}
getVersion={getVersion}
checkUpdateFlag={checkUpdateFlag}
/>
</div>
</div>
</div>
</div>
</>
);
};
Footer.propTypes = { Footer.propTypes = {
dnsVersion: PropTypes.string, dnsVersion: PropTypes.string,
@ -112,4 +115,4 @@ Footer.propTypes = {
checkUpdateFlag: PropTypes.bool, checkUpdateFlag: PropTypes.bool,
}; };
export default withTranslation()(Footer); export default Footer;

View File

@ -588,3 +588,10 @@ export const formatElapsedMs = (elapsedMs, t) => {
.toFixed(2); .toFixed(2);
return `${formattedElapsedMs} ${t('milliseconds_abbreviation')}`; return `${formattedElapsedMs} ${t('milliseconds_abbreviation')}`;
}; };
/**
* @param language {string}
*/
export const setHtmlLangAttr = (language) => {
window.document.documentElement.lang = language;
};

View File

@ -33,6 +33,7 @@ import hr from './__locales/hr.json';
import fa from './__locales/fa.json'; import fa from './__locales/fa.json';
import th from './__locales/th.json'; import th from './__locales/th.json';
import ro from './__locales/ro.json'; import ro from './__locales/ro.json';
import { setHtmlLangAttr } from './helpers/helpers';
const resources = { const resources = {
en: { en: {
@ -143,10 +144,12 @@ i18n
wait: true, wait: true,
}, },
whitelist: availableLanguages, whitelist: availableLanguages,
}, () => { },
() => {
if (!availableLanguages.includes(i18n.language)) { if (!availableLanguages.includes(i18n.language)) {
i18n.changeLanguage(BASE_LOCALE); i18n.changeLanguage(BASE_LOCALE);
} }
setHtmlLangAttr(i18n.language);
}); });
export default i18n; export default i18n;