From 1910da53ecc3ae849e313616260f230976eac727 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sun, 14 Oct 2018 15:12:40 +0200 Subject: [PATCH] fix: reduce main bundle size (exclude locale data) By not loading locale data into the main process we can considerably reduce it's size. We the only thing we need access to in the main process is the translation sets (used for the languages menu). refactor the i18n code so that the locale data can only be loaded when needed (in the renderer). --- app/components/Settings/Locale/Locale.js | 2 +- app/index.js | 14 +- app/lib/i18n/index.js | 133 ++++++++++++++ app/lib/i18n/locale.js | 43 +++++ app/lib/i18n/translation.js | 45 +++++ app/lib/utils/i18n.js | 220 ----------------------- app/lib/zap/menuBuilder.js | 2 +- app/reducers/locale.js | 4 +- app/reducers/ticker.js | 2 +- 9 files changed, 238 insertions(+), 227 deletions(-) create mode 100644 app/lib/i18n/index.js create mode 100644 app/lib/i18n/locale.js create mode 100644 app/lib/i18n/translation.js delete mode 100644 app/lib/utils/i18n.js diff --git a/app/components/Settings/Locale/Locale.js b/app/components/Settings/Locale/Locale.js index e9819deb..ade7cca9 100644 --- a/app/components/Settings/Locale/Locale.js +++ b/app/components/Settings/Locale/Locale.js @@ -1,7 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import FaAngleLeft from 'react-icons/lib/fa/angle-left' -import { getLanguageName } from 'lib/utils/i18n' +import { getLanguageName } from 'lib/i18n' import Isvg from 'react-inlinesvg' import checkIcon from 'icons/check.svg' diff --git a/app/index.js b/app/index.js index 5ba3e1dc..ecb3c6f5 100644 --- a/app/index.js +++ b/app/index.js @@ -5,15 +5,25 @@ import jstz from 'jstimezonedetect' import Root from './containers/Root' import { configureStore, history } from './store/configureStore' +import { getLocale } from './lib/i18n' + +// Load global styles. import './styles/app.global.scss' -import { translationMessages, getLocale } from './lib/utils/i18n' +// Register supported locales. +import './lib/i18n/locale' + +// Get translations. +import translations from './lib/i18n/translation' +// Determine the users current locale. const locale = getLocale() + +// Initialise the intl store with data from the users current locale. const initialState = { intl: { locale, - messages: translationMessages[locale], + messages: translations[locale], timeZone: jstz.determine().name() } } diff --git a/app/lib/i18n/index.js b/app/lib/i18n/index.js new file mode 100644 index 00000000..4e53e2c6 --- /dev/null +++ b/app/lib/i18n/index.js @@ -0,0 +1,133 @@ +import { app, remote } from 'electron' +import Store from 'electron-store' +import get from 'lodash.get' +import { lookup } from 'country-data-lookup' +import createDebug from 'debug' +import isRenderer from 'is-electron-renderer' + +// Defaine list of language that we will support. +export const locales = [ + 'bg', + 'cs', + 'de', + 'el', + 'en', + 'es', + 'fr', + 'ga', + 'hr', + 'ja', + 'nl', + 'pt', + 'ro', + 'ru', + 'sv', + 'tr', + 'uk', + 'zh-CN', + 'zh-TW' +] + +// Defaine list of currencies that we will support. +export const currencies = [ + 'USD', + 'EUR', + 'JPY', + 'GBP', + 'CAD', + 'KRW', + 'AUD', + 'BRL', + 'CHF', + 'CLP', + 'CNY', + 'DKK', + 'HKD', + 'INR', + 'ISK', + 'NZD', + 'PLN', + 'RUB', + 'SEK', + 'SGD', + 'THB', + 'TWB' +] + +/** + * Debugger that does not log in the renderer process. + */ +const debuger = createDebug('zap:i18n') +const debug = (...args) => { + if (!isRenderer) { + debuger(args) + } +} + +/** + * Get the most appropriate language code. + * @return {string} Language code. + */ +export const getLocale = () => { + const store = new Store({ name: 'settings' }) + const userLocale = store.get('locale') + if (userLocale) { + debug('Determined locale as %s from settings', userLocale) + return userLocale + } + const defaultLocale = (app || remote.app).getLocale() || 'en-US' + const language = defaultLocale.toLowerCase().split(/[_-]+/)[0] + let locale = 'en' + if (locales.includes(language)) { + locale = language + } + if (locales.includes(defaultLocale)) { + locale = userLocale + } + debug('Determined locale as %s', locale) + return locale +} + +/** + * Get the most appropriate language code. + * @return {string} Language code. + */ +export const getLanguageName = lang => { + const customNames = { + el: 'Greek', + 'zh-CN': 'Chinese (Simplified, PRC)', + 'zh-TW': 'Chinese (Traditional, Taiwan)' + } + if (customNames[lang]) { + return customNames[lang] + } + + const language = lang.toLowerCase().split(/[_-]+/)[0] + const data = lookup.languages({ alpha2: language }) + const name = get(data, '[0]name', language) + debug('Determined language as %s', name) + return name +} + +/** + * Get the most appropriate currency code. + * @return {string} Currency code. + */ +export const getCurrency = () => { + const store = new Store({ name: 'settings' }) + const userCurrency = store.get('fiatTicker') + if (userCurrency) { + debug('Determined currency as %s from settings', userCurrency) + return userCurrency + } + const defaultLocale = (app || remote.app).getLocale() || 'en-US' + const country = defaultLocale.split(/[_-]+/)[1] + const data = lookup.countries({ alpha2: country }) + const detectedCurrency = get(data, '[0]currencies[0]', 'USD') + let currency = 'USD' + if (currencies.includes(detectedCurrency)) { + currency = detectedCurrency + } + debug('Determined currency as %s', currency) + return currency +} diff --git a/app/lib/i18n/locale.js b/app/lib/i18n/locale.js new file mode 100644 index 00000000..7e01e111 --- /dev/null +++ b/app/lib/i18n/locale.js @@ -0,0 +1,43 @@ +import { addLocaleData } from 'react-intl' + +// Load locale data. +import bg from 'react-intl/locale-data/bg' +import cs from 'react-intl/locale-data/cs' +import de from 'react-intl/locale-data/de' +import el from 'react-intl/locale-data/el' +import en from 'react-intl/locale-data/en' +import es from 'react-intl/locale-data/es' +import fr from 'react-intl/locale-data/fr' +import ga from 'react-intl/locale-data/ga' +import hr from 'react-intl/locale-data/hr' +import ja from 'react-intl/locale-data/ja' +import nl from 'react-intl/locale-data/nl' +import pt from 'react-intl/locale-data/pt' +import ro from 'react-intl/locale-data/ro' +import ru from 'react-intl/locale-data/ru' +import sv from 'react-intl/locale-data/sv' +import tr from 'react-intl/locale-data/tr' +import uk from 'react-intl/locale-data/uk' +import zh from 'react-intl/locale-data/zh' + +// Add locale data. +addLocaleData([ + ...bg, + ...cs, + ...de, + ...el, + ...en, + ...es, + ...fr, + ...ga, + ...hr, + ...ja, + ...nl, + ...pt, + ...ro, + ...ru, + ...sv, + ...tr, + ...uk, + ...zh +]) diff --git a/app/lib/i18n/translation.js b/app/lib/i18n/translation.js new file mode 100644 index 00000000..e1e36996 --- /dev/null +++ b/app/lib/i18n/translation.js @@ -0,0 +1,45 @@ +// Load translation data. +import bgTranslationMessages from '../../translations/bg-BG.json' +import csTranslationMessages from '../../translations/cs-CZ.json' +import deTranslationMessages from '../../translations/de-DE.json' +import elTranslationMessages from '../../translations/el-GR.json' +import enTranslationMessages from '../../translations/en.json' +import esTranslationMessages from '../../translations/es-ES.json' +import frTranslationMessages from '../../translations/fr-FR.json' +import gaTranslationMessages from '../../translations/ga-IE.json' +import hrTranslationMessages from '../../translations/hr-HR.json' +import jaTranslationMessages from '../../translations/ja-JP.json' +import nlTranslationMessages from '../../translations/nl-NL.json' +import ptTranslationMessages from '../../translations/pt-BR.json' +import roTranslationMessages from '../../translations/ro-RO.json' +import ruTranslationMessages from '../../translations/ru-RU.json' +import svTranslationMessages from '../../translations/sv-SE.json' +import trTranslationMessages from '../../translations/tr-TR.json' +import ukTranslationMessages from '../../translations/uk-UA.json' +import zhCNTranslationMessages from '../../translations/zh-CN.json' +import zhTWTranslationMessages from '../../translations/zh-TW.json' + +// Collate all translations. +const translations = { + en: enTranslationMessages, + bg: bgTranslationMessages, + 'zh-CN': zhCNTranslationMessages, + 'zh-TW': zhTWTranslationMessages, + hr: hrTranslationMessages, + cs: csTranslationMessages, + nl: nlTranslationMessages, + fr: frTranslationMessages, + ga: gaTranslationMessages, + de: deTranslationMessages, + el: elTranslationMessages, + ja: jaTranslationMessages, + pt: ptTranslationMessages, + ro: roTranslationMessages, + ru: ruTranslationMessages, + es: esTranslationMessages, + sv: svTranslationMessages, + tr: trTranslationMessages, + uk: ukTranslationMessages +} + +export default translations diff --git a/app/lib/utils/i18n.js b/app/lib/utils/i18n.js deleted file mode 100644 index e7c9878a..00000000 --- a/app/lib/utils/i18n.js +++ /dev/null @@ -1,220 +0,0 @@ -import { app, remote } from 'electron' -import { addLocaleData } from 'react-intl' -import Store from 'electron-store' -import get from 'lodash.get' -import { lookup } from 'country-data-lookup' -import createDebug from 'debug' -import isRenderer from 'is-electron-renderer' - -// Load locale data. -import bg from 'react-intl/locale-data/bg' -import cs from 'react-intl/locale-data/cs' -import de from 'react-intl/locale-data/de' -import el from 'react-intl/locale-data/el' -import en from 'react-intl/locale-data/en' -import es from 'react-intl/locale-data/es' -import fr from 'react-intl/locale-data/fr' -import ga from 'react-intl/locale-data/ga' -import hr from 'react-intl/locale-data/hr' -import ja from 'react-intl/locale-data/ja' -import nl from 'react-intl/locale-data/nl' -import pt from 'react-intl/locale-data/pt' -import ro from 'react-intl/locale-data/ro' -import ru from 'react-intl/locale-data/ru' -import sv from 'react-intl/locale-data/sv' -import tr from 'react-intl/locale-data/tr' -import uk from 'react-intl/locale-data/uk' -import zh from 'react-intl/locale-data/zh' - -// Load translation data. -import bgTranslationMessages from '../../translations/bg-BG.json' -import csTranslationMessages from '../../translations/cs-CZ.json' -import deTranslationMessages from '../../translations/de-DE.json' -import elTranslationMessages from '../../translations/el-GR.json' -import enTranslationMessages from '../../translations/en.json' -import esTranslationMessages from '../../translations/es-ES.json' -import frTranslationMessages from '../../translations/fr-FR.json' -import gaTranslationMessages from '../../translations/ga-IE.json' -import hrTranslationMessages from '../../translations/hr-HR.json' -import jaTranslationMessages from '../../translations/ja-JP.json' -import nlTranslationMessages from '../../translations/nl-NL.json' -import ptTranslationMessages from '../../translations/pt-BR.json' -import roTranslationMessages from '../../translations/ro-RO.json' -import ruTranslationMessages from '../../translations/ru-RU.json' -import svTranslationMessages from '../../translations/sv-SE.json' -import trTranslationMessages from '../../translations/tr-TR.json' -import ukTranslationMessages from '../../translations/uk-UA.json' -import zhCNTranslationMessages from '../../translations/zh-CN.json' -import zhTWTranslationMessages from '../../translations/zh-TW.json' - -/** - * Debugger that does not log in the renderer process. - */ -const debuger = createDebug('zap:i18n') -const debug = (...args) => { - if (!isRenderer) { - debuger(args) - } -} - -// Add locale data. -addLocaleData([ - ...bg, - ...cs, - ...de, - ...el, - ...en, - ...es, - ...fr, - ...ga, - ...hr, - ...ja, - ...nl, - ...pt, - ...ro, - ...ru, - ...sv, - ...tr, - ...uk, - ...zh -]) - -// Defaine list of language that we will support. -export const locales = [ - 'bg', - 'cs', - 'de', - 'el', - 'en', - 'es', - 'fr', - 'ga', - 'hr', - 'ja', - 'nl', - 'pt', - 'ro', - 'ru', - 'sv', - 'tr', - 'uk', - 'zh-CN', - 'zh-TW' -] - -// Defaine list of currencies that we will support. -export const currencies = [ - 'USD', - 'EUR', - 'JPY', - 'GBP', - 'CAD', - 'KRW', - 'AUD', - 'BRL', - 'CHF', - 'CLP', - 'CNY', - 'DKK', - 'HKD', - 'INR', - 'ISK', - 'NZD', - 'PLN', - 'RUB', - 'SEK', - 'SGD', - 'THB', - 'TWB' -] - -// Collate all translations. -export const translationMessages = { - en: enTranslationMessages, - bg: bgTranslationMessages, - 'zh-CN': zhCNTranslationMessages, - 'zh-TW': zhTWTranslationMessages, - hr: hrTranslationMessages, - cs: csTranslationMessages, - nl: nlTranslationMessages, - fr: frTranslationMessages, - ga: gaTranslationMessages, - de: deTranslationMessages, - el: elTranslationMessages, - ja: jaTranslationMessages, - pt: ptTranslationMessages, - ro: roTranslationMessages, - ru: ruTranslationMessages, - es: esTranslationMessages, - sv: svTranslationMessages, - tr: trTranslationMessages, - uk: ukTranslationMessages -} - -/** - * Get the most appropriate language code. - * @return {string} Language code. - */ -export const getLocale = () => { - const store = new Store({ name: 'settings' }) - const userLocale = store.get('locale') - if (userLocale) { - debug('Determined locale as %s from settings', userLocale) - return userLocale - } - const defaultLocale = (app || remote.app).getLocale() || 'en-US' - const language = defaultLocale.toLowerCase().split(/[_-]+/)[0] - let locale = 'en' - if (locales.includes(language)) { - locale = language - } - if (locales.includes(defaultLocale)) { - locale = userLocale - } - debug('Determined locale as %s', locale) - return locale -} - -/** - * Get the most appropriate language code. - * @return {string} Language code. - */ -export const getLanguageName = lang => { - const customNames = { - el: 'Greek', - 'zh-CN': 'Chinese (Simplified, PRC)', - 'zh-TW': 'Chinese (Traditional, Taiwan)' - } - if (customNames[lang]) { - return customNames[lang] - } - - const language = lang.toLowerCase().split(/[_-]+/)[0] - const data = lookup.languages({ alpha2: language }) - const name = get(data, '[0]name', language) - debug('Determined language as %s', name) - return name -} - -/** - * Get the most appropriate currency code. - * @return {string} Currency code. - */ -export const getCurrency = () => { - const store = new Store({ name: 'settings' }) - const userCurrency = store.get('fiatTicker') - if (userCurrency) { - debug('Determined currency as %s from settings', userCurrency) - return userCurrency - } - const defaultLocale = (app || remote.app).getLocale() || 'en-US' - const country = defaultLocale.split(/[_-]+/)[1] - const data = lookup.countries({ alpha2: country }) - const detectedCurrency = get(data, '[0]currencies[0]', 'USD') - let currency = 'USD' - if (currencies.includes(detectedCurrency)) { - currency = detectedCurrency - } - debug('Determined currency as %s', currency) - return currency -} diff --git a/app/lib/zap/menuBuilder.js b/app/lib/zap/menuBuilder.js index b1f12d7a..0bee78a5 100644 --- a/app/lib/zap/menuBuilder.js +++ b/app/lib/zap/menuBuilder.js @@ -1,6 +1,6 @@ // @flow import { app, Menu, shell, BrowserWindow, ipcMain } from 'electron' -import { locales, getLocale, getLanguageName } from '../utils/i18n' +import { getLocale, getLanguageName, locales } from '../i18n' export default class ZapMenuBuilder { mainWindow: BrowserWindow diff --git a/app/reducers/locale.js b/app/reducers/locale.js index a5997d58..1538259d 100644 --- a/app/reducers/locale.js +++ b/app/reducers/locale.js @@ -1,7 +1,7 @@ import Store from 'electron-store' import { updateIntl } from 'react-intl-redux' import { ipcRenderer } from 'electron' -import { translationMessages } from 'lib/utils/i18n' +import translations from 'lib/i18n/translation' // Settings store const store = new Store({ name: 'settings' }) @@ -35,6 +35,6 @@ export const receiveLocale = (event, locale) => dispatch => { // ------------------------------------ // Reducer // ------------------------------------ -export default function localeReducer(state = translationMessages) { +export default function localeReducer(state = translations) { return state } diff --git a/app/reducers/ticker.js b/app/reducers/ticker.js index 771b9fec..22327094 100644 --- a/app/reducers/ticker.js +++ b/app/reducers/ticker.js @@ -1,7 +1,7 @@ import { createSelector } from 'reselect' import Store from 'electron-store' import { requestTicker } from 'lib/utils/api' -import { currencies, getCurrency } from 'lib/utils/i18n' +import { currencies, getCurrency } from 'lib/i18n' import { infoSelectors } from './info' // Settings store