Browse Source

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).
renovate/lint-staged-8.x
Tom Kirkpatrick 6 years ago
parent
commit
1910da53ec
No known key found for this signature in database GPG Key ID: 72203A8EC5967EA8
  1. 2
      app/components/Settings/Locale/Locale.js
  2. 14
      app/index.js
  3. 133
      app/lib/i18n/index.js
  4. 43
      app/lib/i18n/locale.js
  5. 45
      app/lib/i18n/translation.js
  6. 220
      app/lib/utils/i18n.js
  7. 2
      app/lib/zap/menuBuilder.js
  8. 4
      app/reducers/locale.js
  9. 2
      app/reducers/ticker.js

2
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'

14
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()
}
}

133
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
}

43
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
])

45
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

220
app/lib/utils/i18n.js

@ -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
}

2
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

4
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
}

2
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

Loading…
Cancel
Save