From 885d6eaa4d7c4b99f4233e42a1fec85a3f685927 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sun, 11 Dec 2016 17:42:35 +0100 Subject: [PATCH] i18n string dictionaries (#3532) * TabBar & Settings -> Views i18n enabled * Proxy i18n * Settings i18n * defaultLocale * Introduce thin Translate wrapper * PropTypes util caters for multiples * Translate & LanguageSelector under ui * Update location & proptypes * Add UI Language selector * German settings pages * Add German language selection * Corrected umlaut encoding * Lint * Re-apply pre-merge conflict changes * better German i18n * Language names in locale language * i8n -> index * Allow for development/production operation * Use Yahoo react-intl (as opposed to react-i18nify) * Use default messages wih expansions * Remove non-reused variable definitions * Use FormattedMessage directly, opens up WebPack & Babel opportunities * Add flat to flatten * Extract default messages via babel * Webpack to aggegrate i18n defaultMessage * Re-add react-intl after merge * Update proptype references (merge) * Strip down external dictionary * i18n for dapps * Restore tests submodule * Allow language changes to reflect * Style updates --- js/.babelrc | 15 +- js/package.json | 4 + js/src/i18n/de/index.js | 21 +++ js/src/i18n/de/settings.js | 96 +++++++++++ js/src/i18n/en/index.js | 21 +++ js/src/i18n/en/settings.js | 63 ++++++++ js/src/i18n/index.js | 21 +++ js/src/i18n/languages.js | 20 +++ js/src/i18n/store.js | 62 +++++++ js/src/ui/ContextProvider/contextProvider.js | 16 +- js/src/ui/Form/Select/select.js | 8 +- js/src/ui/LanguageSelector/index.js | 17 ++ .../ui/LanguageSelector/languageSelector.js | 71 ++++++++ js/src/ui/index.js | 6 +- js/src/views/Application/TabBar/tabBar.js | 109 ++++--------- js/src/views/Dapps/AddDapps/AddDapps.js | 51 +++++- js/src/views/Dapps/dapps.js | 25 ++- .../views/Settings/Background/background.js | 23 ++- js/src/views/Settings/Parity/parity.js | 80 +++++---- js/src/views/Settings/Proxy/proxy.js | 35 +++- js/src/views/Settings/Views/defaults.js | 28 +--- js/src/views/Settings/Views/views.js | 153 ++++++++++++++---- js/src/views/Settings/settings.js | 25 ++- js/webpack/app.js | 9 ++ 24 files changed, 783 insertions(+), 196 deletions(-) create mode 100644 js/src/i18n/de/index.js create mode 100644 js/src/i18n/de/settings.js create mode 100644 js/src/i18n/en/index.js create mode 100644 js/src/i18n/en/settings.js create mode 100644 js/src/i18n/index.js create mode 100644 js/src/i18n/languages.js create mode 100644 js/src/i18n/store.js create mode 100644 js/src/ui/LanguageSelector/index.js create mode 100644 js/src/ui/LanguageSelector/languageSelector.js diff --git a/js/.babelrc b/js/.babelrc index 9f44b6bd2..a4f2a2006 100644 --- a/js/.babelrc +++ b/js/.babelrc @@ -13,18 +13,19 @@ "retainLines": true, "env": { "production": { - "plugins": ["transform-react-remove-prop-types"] + "plugins": [ + "transform-react-remove-prop-types" + ] }, "development": { - "plugins": ["react-hot-loader/babel"] + "plugins": [ + "react-hot-loader/babel", + ["react-intl", { "messagesDir": "./.build/i18n/" }] + ] }, "test": { "plugins": [ - [ - "babel-plugin-webpack-alias", { - "config": "webpack/test.js" - } - ] + ["babel-plugin-webpack-alias", { "config": "webpack/test.js" }] ] } } diff --git a/js/package.json b/js/package.json index 9f8eabc2c..525211517 100644 --- a/js/package.json +++ b/js/package.json @@ -52,6 +52,7 @@ "babel-eslint": "7.1.1", "babel-loader": "6.2.8", "babel-plugin-lodash": "3.2.10", + "babel-plugin-react-intl": "2.2.0", "babel-plugin-transform-class-properties": "6.18.0", "babel-plugin-transform-decorators-legacy": "1.3.4", "babel-plugin-transform-object-rest-spread": "6.20.2", @@ -111,6 +112,7 @@ "react-addons-perf": "15.4.1", "react-addons-test-utils": "15.4.1", "react-hot-loader": "3.0.0-beta.6", + "react-intl-aggregate-webpack-plugin": "0.0.1", "rucksack-css": "0.9.1", "sinon": "1.17.6", "sinon-as-promised": "4.0.2", @@ -133,6 +135,7 @@ "ethereumjs-tx": "1.1.4", "eventemitter3": "2.0.2", "file-saver": "1.3.3", + "flat": "2.0.1", "format-json": "1.0.3", "format-number": "2.0.1", "geopattern": "1.2.3", @@ -155,6 +158,7 @@ "react-copy-to-clipboard": "4.2.3", "react-dom": "15.4.1", "react-dropzone": "3.7.3", + "react-intl": "2.1.5", "react-redux": "4.4.6", "react-router": "3.0.0", "react-router-redux": "4.0.7", diff --git a/js/src/i18n/de/index.js b/js/src/i18n/de/index.js new file mode 100644 index 000000000..d8c0f9b4b --- /dev/null +++ b/js/src/i18n/de/index.js @@ -0,0 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import settings from './settings'; + +export default { + settings +}; diff --git a/js/src/i18n/de/settings.js b/js/src/i18n/de/settings.js new file mode 100644 index 000000000..9142ff9c7 --- /dev/null +++ b/js/src/i18n/de/settings.js @@ -0,0 +1,96 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + label: 'Einstellungen', + + background: { + label: 'Hintergrund', + + overview_0: 'Dein Hintergrundmuster ist einzigartig und beruht auf deiner Parity-Installation. Es ändert sich immer dann, wenn du ein neues Signer-Token erstellst. So können dezentrale Applicationen keine Vertrauenswürdigkeit vortäuschen.', + overview_1: 'Such dir ein Muster aus und merke es dir. Dieses Muster wird dir von nun an immer angezeigt, es sei denn du löschst deinen Browser-Cache oder benutzt ein neues Signer-Token.', + + button_more: 'weitere generieren' + }, + + parity: { + label: 'Parity', + + overview_0: 'Diese Einstellungen verändern das Verhalten deines Parity-Knotens.', + + languages: { + label: 'Anzeigesprache', + hint: 'Die Sprache, in der dir diese Obefläche angezeigt wird' + }, + + modes: { + label: 'Betriebsmodus', + hint: 'Der Synchronisations-Modus deines Parity-Knotens', + + mode_active: 'Parity synchronisiert kontinuierlich die Blockchain', + mode_passive: 'Parity synchronisiert zu Beginn, schläft dann und wacht regelmäßig zum Synchronisieren auf', + mode_dark: 'Parity synchronisiert nur falls erforderlich, etwa wenn es aus der Ferne aufgerufen wird', + mode_offline: 'Parity synchronisiert nicht' + } + }, + + proxy: { + label: 'Proxy', + + overview_0: 'Die Proxy-Einstellungen ermöglichen dir einen einfachen Zugriff über einprägsame Adressen, auf die Oberfläche mit all ihren dezentralen Anwendungen.', + + details_0: 'Anstelle des Zugriffs über IP-Adresse und Port wirst du über die .parity-Subdomain auf die Parity-Oberfläche zugreifen können, indem du {homeProxy} besuchst. Dafür musst du folgenden Eintrag in den Proxy-Einstellungen deines Browsers hinzufügen:', + details_1: 'Hier findest du Anleitungen zum Anpassen der Proxy-Einstellungen in {windowsLink}, {macOSLink} oder {ubuntuLink}.' + }, + + views: { + label: 'Ansicht', + + overview_0: 'Hier kannst du entscheiden, welche Teile der Parity-Oberfläche dir angezeigt werden sollen.', + overview_1: 'Benutzt du Parity ganz normal? Die Standardeinstellungen sind gleichermaßen für Einsteigende als auch für Fortgeschrittene gedacht.', + overview_2: 'Entwickelst du mit Parity? Füge zum Beispiel den Reiter "Contracts" zu deiner Ansicht hinzu.', + overview_3: 'Bist du Miner oder betreibst du einen großen Knoten? Füge den Reiter "Status" hinzu, um alle Information über den Betrieb deines Knotens im Blick zu halten.', + + accounts: { + label: 'Konten', + description: 'Eine Liste aller Konten, die mit dieser Parity-Installation verbunden sind. Sende Transaktionen, empfange eingehende Beträge, verwalte deine Kontostände oder lade deine Konten auf.' + }, + addresses: { + label: 'Adressbuch', + description: 'Eine Liste all deiner Kontakte und der Adressen, die von dieser Parity-Installation verwaltet werden. Überwache Konten und gelange mit nur einem Klick zu Details deiner Transaktionen.' + }, + apps: { + label: 'Anwendungen', + description: 'Dezentrale Anwendungen, die mit dem Netzwerk interagieren. Füge Anwendungen hinzu, entferne oder öffne Anwendungen.' + }, + contracts: { + label: 'Contracts', + description: 'Interagiere mit Smart Contracts im Netzwerk. Diese Umgebung ist auf Fortgeschrittene mit gutem Verständnis der Fuktionsweise von Smart Contracts zugeschnitten.' + }, + status: { + label: 'Status', + description: 'Schau dir an, wie sich dein Parity-Knoten schlägt. Hier findest du zum Beispiel die Anzahl der aktuellen Verbindungen zum Netzwerk, Logs deiner laufenden Instanz und (sofern konfiguriert) Details zum Mining.' + }, + signer: { + label: 'Signer', + description: 'In diesem sicheren Bereich kannst du Transaktionen, die von dir oder von dezentralen Anwendungen erstellt wurden, prüfen und dann genehmigen oder ablehnen.' + }, + settings: { + label: 'Einstellungen', + description: 'Diese Seite. Pass die Parity-Oberfläche nach deinen Wünschen an.' + } + } +}; diff --git a/js/src/i18n/en/index.js b/js/src/i18n/en/index.js new file mode 100644 index 000000000..d8c0f9b4b --- /dev/null +++ b/js/src/i18n/en/index.js @@ -0,0 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import settings from './settings'; + +export default { + settings +}; diff --git a/js/src/i18n/en/settings.js b/js/src/i18n/en/settings.js new file mode 100644 index 000000000..a0e7c7f1f --- /dev/null +++ b/js/src/i18n/en/settings.js @@ -0,0 +1,63 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + label: 'settings', + + background: { + label: 'background' + }, + + parity: { + label: 'parity' + }, + + proxy: { + label: 'proxy' + }, + + views: { + label: 'views', + + accounts: { + label: 'Accounts' + }, + + addresses: { + label: 'Addressbook' + }, + + apps: { + label: 'Applications' + }, + + contracts: { + label: 'Contracts' + }, + + status: { + label: 'Status' + }, + + signer: { + label: 'Signer' + }, + + settings: { + label: 'Settings' + } + } +}; diff --git a/js/src/i18n/index.js b/js/src/i18n/index.js new file mode 100644 index 000000000..4ed119c90 --- /dev/null +++ b/js/src/i18n/index.js @@ -0,0 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import LocaleStore from './store'; + +export { + LocaleStore +}; diff --git a/js/src/i18n/languages.js b/js/src/i18n/languages.js new file mode 100644 index 000000000..f4950e401 --- /dev/null +++ b/js/src/i18n/languages.js @@ -0,0 +1,20 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + de: 'Deutsch', + en: 'English' +}; diff --git a/js/src/i18n/store.js b/js/src/i18n/store.js new file mode 100644 index 000000000..f171497e4 --- /dev/null +++ b/js/src/i18n/store.js @@ -0,0 +1,62 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import flatten from 'flat'; +import { action, observable, transaction } from 'mobx'; +import { addLocaleData } from 'react-intl'; +import de from 'react-intl/locale-data/de'; +import en from 'react-intl/locale-data/en'; + +import languages from './languages'; +import deMessages from './de'; +import enMessages from './en'; + +let instance = null; +const isProduction = process.env.NODE_ENV === 'production'; + +const DEFAULT = 'en'; +const LANGUAGES = flatten({ languages }); +const MESSAGES = { + de: Object.assign(flatten(deMessages), LANGUAGES), + en: Object.assign(flatten(enMessages), LANGUAGES) +}; +const LOCALES = isProduction + ? ['en'] + : ['en', 'de']; + +addLocaleData([...de, ...en]); + +export default class Store { + @observable locale = DEFAULT; + @observable locales = LOCALES; + @observable messages = MESSAGES[DEFAULT]; + @observable isDevelopment = !isProduction; + + @action setLocale (locale) { + transaction(() => { + this.locale = locale; + this.messages = MESSAGES[locale]; + }); + } + + static get () { + if (!instance) { + instance = new Store(); + } + + return instance; + } +} diff --git a/js/src/ui/ContextProvider/contextProvider.js b/js/src/ui/ContextProvider/contextProvider.js index 7af6d342e..543730c40 100644 --- a/js/src/ui/ContextProvider/contextProvider.js +++ b/js/src/ui/ContextProvider/contextProvider.js @@ -14,8 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { Component, PropTypes } from 'react'; +import React, { Component, PropTypes } from 'react'; +import { IntlProvider } from 'react-intl'; +import { observer } from 'mobx-react'; +import { LocaleStore } from '../../i18n'; + +@observer export default class ContextProvider extends Component { static propTypes = { api: PropTypes.object.isRequired, @@ -30,10 +35,17 @@ export default class ContextProvider extends Component { store: PropTypes.object } + localeStore = LocaleStore.get(); + render () { const { children } = this.props; + const { locale, messages } = this.localeStore; - return children; + return ( + + { children } + + ); } getChildContext () { diff --git a/js/src/ui/Form/Select/select.js b/js/src/ui/Form/Select/select.js index cb879e3f7..b966f483c 100644 --- a/js/src/ui/Form/Select/select.js +++ b/js/src/ui/Form/Select/select.js @@ -17,6 +17,8 @@ import React, { Component, PropTypes } from 'react'; import { SelectField } from 'material-ui'; +import { nodeOrStringProptype } from '~/util/proptypes'; + // TODO: duplicated in Input const UNDERLINE_DISABLED = { borderColor: 'rgba(255, 255, 255, 0.298039)' // 'transparent' // 'rgba(255, 255, 255, 0.298039)' @@ -33,9 +35,9 @@ export default class Select extends Component { children: PropTypes.node, className: PropTypes.string, disabled: PropTypes.bool, - error: PropTypes.string, - hint: PropTypes.string, - label: PropTypes.string, + error: nodeOrStringProptype(), + hint: nodeOrStringProptype(), + label: nodeOrStringProptype(), onBlur: PropTypes.func, onChange: PropTypes.func, onKeyDown: PropTypes.func, diff --git a/js/src/ui/LanguageSelector/index.js b/js/src/ui/LanguageSelector/index.js new file mode 100644 index 000000000..772167d14 --- /dev/null +++ b/js/src/ui/LanguageSelector/index.js @@ -0,0 +1,17 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './languageSelector'; diff --git a/js/src/ui/LanguageSelector/languageSelector.js b/js/src/ui/LanguageSelector/languageSelector.js new file mode 100644 index 000000000..db8949510 --- /dev/null +++ b/js/src/ui/LanguageSelector/languageSelector.js @@ -0,0 +1,71 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { MenuItem } from 'material-ui'; +import { observer } from 'mobx-react'; + +import Select from '../Form/Select'; +import { LocaleStore } from '../../i18n'; + +@observer +export default class LanguageSelector extends Component { + store = LocaleStore.get(); + + render () { + if (!this.store.isDevelopment) { + return null; + } + + return ( + + ); + } + + renderOptions () { + return this.store.locales.map((locale) => { + const label = ; + + return ( + + { label } + + ); + }); + } + + onChange = (event, index, locale) => { + this.store.setLocale(locale); + } +} diff --git a/js/src/ui/index.js b/js/src/ui/index.js index c5a965458..7cf3e7ee5 100644 --- a/js/src/ui/index.js +++ b/js/src/ui/index.js @@ -34,6 +34,7 @@ import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAd import GasPriceEditor from './GasPriceEditor'; import IdentityIcon from './IdentityIcon'; import IdentityName from './IdentityName'; +import LanguageSelector from './LanguageSelector'; import Loading from './Loading'; import MethodDecoding from './MethodDecoding'; import Modal, { Busy as BusyStep, Completed as CompletedStep } from './Modal'; @@ -74,10 +75,10 @@ export { InputAddressSelect, InputChip, InputInline, - Loading, - Select, IdentityIcon, IdentityName, + LanguageSelector, + Loading, MethodDecoding, Modal, BusyStep, @@ -87,6 +88,7 @@ export { ParityBackground, RadioButtons, ShortenedHash, + Select, SignerIcon, Tags, Tooltip, diff --git a/js/src/views/Application/TabBar/tabBar.js b/js/src/views/Application/TabBar/tabBar.js index 63f569f1f..ad2bfb779 100644 --- a/js/src/views/Application/TabBar/tabBar.js +++ b/js/src/views/Application/TabBar/tabBar.js @@ -15,6 +15,7 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; +import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar'; @@ -23,85 +24,57 @@ import { isEqual } from 'lodash'; import { Badge, Tooltip } from '~/ui'; +import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg'; + import styles from './tabBar.css'; -import imagesEthcoreBlock from '../../../../assets/images/parity-logo-white-no-text.svg'; class Tab extends Component { static propTypes = { - view: PropTypes.object, children: PropTypes.node, - pendings: PropTypes.number + pendings: PropTypes.number, + view: PropTypes.object }; - shouldComponentUpdate (nextProps) { - return (nextProps.view.id === 'signer' && nextProps.pendings !== this.props.pendings); - } - render () { const { view, children } = this.props; - const label = this.getLabel(view); - return ( + label={ + view.id === 'signer' + ? this.renderSignerLabel(view.id) + : this.renderLabel(view.id) + }> { children } ); } - getLabel (view) { - const { label } = view; - - if (view.id === 'signer') { - return this.renderSignerLabel(label); - } - - if (view.id === 'status') { - return this.renderStatusLabel(label); - } - - return this.renderLabel(label); - } - - renderLabel (name, bubble) { + renderLabel (id, bubble) { return (
- { name } + { bubble }
); } - renderSignerLabel (label) { + renderSignerLabel (id) { const { pendings } = this.props; + let bubble; if (pendings) { - const bubble = ( + bubble = ( ); - - return this.renderLabel(label, bubble); } - return this.renderLabel(label); - } - - renderStatusLabel (label) { - // const { isTest, netChain } = this.props; - // const bubble = ( - // - // ); - - return this.renderLabel(label, null); + return this.renderLabel(id, bubble); } } @@ -111,28 +84,19 @@ class TabBar extends Component { }; static propTypes = { - views: PropTypes.array.isRequired, - pending: PropTypes.array, isTest: PropTypes.bool, - netChain: PropTypes.string + netChain: PropTypes.string, + pending: PropTypes.array, + views: PropTypes.array.isRequired }; static defaultProps = { pending: [] }; - shouldComponentUpdate (nextProps, nextState) { - const prevViews = this.props.views.map((v) => v.id).sort(); - const nextViews = nextProps.views.map((v) => v.id).sort(); - - return (nextProps.pending.length !== this.props.pending.length) || - (!isEqual(prevViews, nextViews)); - } - render () { return ( - + { this.renderLogo() } { this.renderTabs() } { this.renderLast() } @@ -167,21 +131,20 @@ class TabBar extends Component { .map((view, index) => { const body = (view.id === 'accounts') ? ( - + ) : null; return ( + className={ styles.tabLink }key={ view.id } + to={ view.route }> + view={ view }> { body } @@ -203,11 +166,10 @@ function mapStateToProps (initState) { .keys(views) .filter((id) => views[id].fixed || views[id].active); - let filteredViews = filteredViewIds - .map((id) => ({ - ...views[id], - id - })); + let filteredViews = filteredViewIds.map((id) => ({ + ...views[id], + id + })); return (state) => { const { views } = state.settings; @@ -221,11 +183,10 @@ function mapStateToProps (initState) { } filteredViewIds = viewIds; - filteredViews = viewIds - .map((id) => ({ - ...views[id], - id - })); + filteredViews = viewIds.map((id) => ({ + ...views[id], + id + })); return { views: filteredViews }; }; diff --git a/js/src/views/Dapps/AddDapps/AddDapps.js b/js/src/views/Dapps/AddDapps/AddDapps.js index 71d03dc50..d3876998a 100644 --- a/js/src/views/Dapps/AddDapps/AddDapps.js +++ b/js/src/views/Dapps/AddDapps/AddDapps.js @@ -15,6 +15,7 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; +import { FormattedMessage } from 'react-intl'; import { observer } from 'mobx-react'; import DoneIcon from 'material-ui/svg-icons/action/done'; import { List, ListItem } from 'material-ui/List'; @@ -39,22 +40,56 @@ export default class AddDapps extends Component { return ( + } actions={ [