Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
feat(i18n): initial multi-language support
Browse files Browse the repository at this point in the history
  • Loading branch information
mrfelton committed Sep 19, 2018
1 parent 54ed782 commit aedd1ee
Show file tree
Hide file tree
Showing 104 changed files with 4,146 additions and 344 deletions.
5 changes: 4 additions & 1 deletion .babelrc
Expand Up @@ -10,7 +10,10 @@
"stage-0",
"react"
],
"plugins": ["add-module-exports", "dynamic-import-webpack"],
"plugins": ["add-module-exports", "dynamic-import-webpack", ["react-intl-auto", {
"removePrefix": "app/",
"filebase": false
}]],
"env": {
"production": {
"presets": ["react-optimize"],
Expand Down
21 changes: 15 additions & 6 deletions app/components/Activity/Activity.js
Expand Up @@ -5,6 +5,8 @@ import searchIcon from 'icons/search.svg'
import xIcon from 'icons/x.svg'
import FaRepeat from 'react-icons/lib/fa/repeat'

import { FormattedMessage, injectIntl } from 'react-intl'

import Wallet from 'components/Wallet'
import LoadingBolt from 'components/LoadingBolt'
import Invoice from './Invoice'
Expand All @@ -13,6 +15,8 @@ import Transaction from './Transaction'

import styles from './Activity.scss'

import messages from './messages'

class Activity extends Component {
constructor(props, context) {
super(props, context)
Expand Down Expand Up @@ -87,7 +91,8 @@ class Activity extends Component {

updateSearchActive,
updateSearchText,
walletProps
walletProps,
intl
} = this.props

if (balance.channelBalance === null || balance.walletBalance === null) {
Expand Down Expand Up @@ -134,7 +139,7 @@ class Activity extends Component {
<header className={`${styles.header} ${styles.search}`}>
<section>
<input
placeholder="Search"
placeholder={intl.formatMessage({ ...messages.search })}
value={searchText}
onChange={event => updateSearchText(event.target.value)}
/>
Expand All @@ -160,7 +165,7 @@ class Activity extends Component {
className={f.key === filter.key ? styles.activeFilter : undefined}
onClick={() => changeFilter(f)}
>
<span>{f.name}</span>
<FormattedMessage {...messages[f.name]} />

<div className={f.key === filter.key ? styles.activeBorder : undefined} />
</li>
Expand All @@ -176,7 +181,7 @@ class Activity extends Component {
this.repeat = ref
}}
>
{refreshing ? <FaRepeat /> : 'Refresh'}
{refreshing ? <FaRepeat /> : <FormattedMessage {...messages.refresh} />}
</span>
</li>
<li className={styles.activeFilter} onClick={() => updateSearchActive(true)}>
Expand Down Expand Up @@ -204,7 +209,11 @@ class Activity extends Component {
{showExpiredToggle && (
<li>
<div className={styles.toggleExpired} onClick={toggleExpiredRequests}>
{showExpiredRequests ? 'Hide Expired Requests' : 'Show Expired Requests'}
{showExpiredRequests ? (
<FormattedMessage {...messages.hide_expired} />
) : (
<FormattedMessage {...messages.show_expired} />
)}
</div>
</li>
)}
Expand Down Expand Up @@ -240,4 +249,4 @@ Activity.propTypes = {
currencyName: PropTypes.string.isRequired
}

export default Activity
export default injectIntl(Activity)
21 changes: 6 additions & 15 deletions app/components/Activity/Activity.scss
Expand Up @@ -284,23 +284,15 @@
font-size: 10px;
}

.icon,
h3,
span {
vertical-align: middle;
}

h3,
span {
font-size: 14px;
font-weight: bold;
letter-spacing: 1.2px;
.date {
font-size: 12px;
}

.icon {
display: inline-block;
flex: none;
position: relative;
vertical-align: middle;
width: 20px;
height: 20px;
background: #31343f;
Expand All @@ -321,17 +313,16 @@

h3 {
display: inline-block;
font-size: 14px;
font-weight: bold;
letter-spacing: 1.2px;

&::after {
content: ' ';
display: inline-block;
width: 3px;
}
}

span {
text-transform: uppercase;
}
}

.amount {
Expand Down
7 changes: 6 additions & 1 deletion app/components/Activity/Countdown/Countdown.js
@@ -1,6 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'

import { FormattedMessage } from 'react-intl'
import messages from './messages'

import styles from './Countdown.scss'

class Countdown extends React.Component {
Expand Down Expand Up @@ -73,7 +76,9 @@ class Countdown extends React.Component {

return (
<span className={styles.container}>
<i className={styles.caption}>Expires in</i>
<i className={styles.caption}>
<FormattedMessage {...messages.expires} />
</i>
<i>{days > 0 && `${days}:`}</i>
<i>{hours > 0 && `${hours}:`}</i>
<i>{minutes > 0 && `${minutes}:`}</i>
Expand Down
6 changes: 6 additions & 0 deletions app/components/Activity/Countdown/messages.js
@@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'

/* eslint-disable max-len */
export default defineMessages({
expires: 'Expires in'
})
31 changes: 22 additions & 9 deletions app/components/Activity/Invoice/Invoice.js
@@ -1,42 +1,55 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import { btc } from 'lib/utils'

import Isvg from 'react-inlinesvg'
import Value from 'components/Value'
import checkmarkIcon from 'icons/check_circle.svg'

import { FormattedTime, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'

import styles from '../Activity.scss'

const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyName }) => (
const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyName, intl }) => (
<div
className={`${styles.container} ${!invoice.settled ? styles.unpaid : undefined}`}
onClick={() => showActivityModal('INVOICE', invoice.payment_request)}
>
<div className={styles.activityTypeIcon}>
<section
className="hint--bottom"
data-hint={`Lightning invoice (${invoice.settled ? 'paid)' : 'unpaid'})`}
data-hint={
invoice.settled
? intl.formatMessage({ ...messages.type_paid })
: intl.formatMessage({ ...messages.type_unpaid })
}
>
<Isvg src={checkmarkIcon} />
</section>
</div>

<div className={styles.data}>
<div className={styles.title}>
<h3>{invoice.settled ? 'Received payment' : 'Requested payment'}</h3>
<h3>
{invoice.settled ? (
<FormattedMessage {...messages.received} />
) : (
<FormattedMessage {...messages.requested} />
)}
</h3>
</div>
<div className={styles.subtitle}>
<Moment format="h:mm a">
{invoice.settled ? invoice.settle_date * 1000 : invoice.creation_date * 1000}
</Moment>
<FormattedTime
value={invoice.settled ? invoice.settle_date * 1000 : invoice.creation_date * 1000}
/>
</div>
</div>
<div
className={`hint--top-left ${styles.amount} ${
invoice.settled ? styles.positive : styles.negative
}`}
data-hint="Invoice amount"
data-hint={intl.formatMessage({ ...messages.amount })}
>
<span>
<i className={styles.plus}>+</i>
Expand Down Expand Up @@ -66,4 +79,4 @@ Invoice.propTypes = {
currencyName: PropTypes.string.isRequired
}

export default Invoice
export default injectIntl(Invoice)
10 changes: 10 additions & 0 deletions app/components/Activity/Invoice/messages.js
@@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'

/* eslint-disable max-len */
export default defineMessages({
received: 'Received payment',
requested: 'Requested payment',
type_paid: 'Lightning invoice (paid)',
type_unpaid: 'Lightning invoice (unpaid)',
amount: 'Invoice amount'
})
47 changes: 36 additions & 11 deletions app/components/Activity/InvoiceModal/InvoiceModal.js
@@ -1,17 +1,18 @@
import React from 'react'
import PropTypes from 'prop-types'

import Moment from 'react-moment'

import QRCode from 'qrcode.react'
import copy from 'copy-to-clipboard'
import { showNotification } from 'lib/utils/notifications'

import FaAngleDown from 'react-icons/lib/fa/angle-down'

import Value from 'components/Value'
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'
import Countdown from '../Countdown'

import messages from './messages'

import styles from './InvoiceModal.scss'

const InvoiceModal = ({
Expand All @@ -29,7 +30,7 @@ const InvoiceModal = ({
}) => {
const copyPaymentRequest = () => {
copy(invoice.payment_request)
showNotification('Noice', 'Successfully copied to clipboard')
showNotification('Noice', <FormattedMessage {...messages.copied} />)
}

const countDownDate = parseInt(invoice.creation_date, 10) + parseInt(invoice.expiry, 10)
Expand All @@ -38,7 +39,9 @@ const InvoiceModal = ({
<div className={styles.container}>
<div className={styles.content}>
<section className={styles.left}>
<h2>Payment Request</h2>
<h2>
<FormattedMessage {...messages.pay_req} />
</h2>
<QRCode
value={invoice.payment_request}
renderAs="svg"
Expand Down Expand Up @@ -80,28 +83,50 @@ const InvoiceModal = ({
</section>
<section className={styles.date}>
<p>
<Moment format="MM/DD/YYYY">{invoice.creation_date * 1000}</Moment>
<FormattedDate
value={invoice.creation_date * 1000}
year="numeric"
month="long"
day="2-digit"
/>{' '}
<FormattedTime value={new Date(invoice.creation_date * 1000)} />
</p>
{!invoice.settled && <p className={styles.notPaid}>Not Paid</p>}
{invoice.settled && <p className={styles.paid}>Paid</p>}
{!invoice.settled && (
<p className={styles.notPaid}>
<FormattedMessage {...messages.not_paid} />
</p>
)}
{invoice.settled && (
<p className={styles.paid}>
<FormattedMessage {...messages.paid} />
</p>
)}
</section>
</div>

<div className={styles.memo}>
<h4>Memo</h4>
<h4>
<FormattedMessage {...messages.memo} />
</h4>
<p>{invoice.memo}</p>
</div>

<div className={styles.request}>
<h4>Request</h4>
<h4>
<FormattedMessage {...messages.request} />
</h4>
<p>{invoice.payment_request}</p>
</div>
</section>
</div>

<div className={styles.actions}>
<div>Save as image</div>
<div onClick={copyPaymentRequest}>Copy Request</div>
<div>
<FormattedMessage {...messages.save} />
</div>
<div onClick={copyPaymentRequest}>
<FormattedMessage {...messages.copy} />
</div>
</div>
</div>
)
Expand Down
12 changes: 12 additions & 0 deletions app/components/Activity/InvoiceModal/messages.js
@@ -0,0 +1,12 @@
import { defineMessages } from 'react-intl'

/* eslint-disable max-len */
export default defineMessages({
copy: 'Copy Request',
pay_req: 'Payment Request',
memo: 'Memo',
request: 'Request',
save: 'Save as image',
not_paid: 'Not Paid',
paid: 'Paid'
})

0 comments on commit aedd1ee

Please sign in to comment.