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 6045ea34..38ff307a 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