Merge branch 'main' into 2022-07-15-add-swedish-translation

This commit is contained in:
Reckless_Satoshi 2022-07-17 20:52:31 +00:00 committed by GitHub
commit de9f83da76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 274 additions and 167 deletions

View File

@ -1574,7 +1574,7 @@ class Logics:
Summarizes a finished order. Returns a dict with Summarizes a finished order. Returns a dict with
amounts, fees, costs, etc, for buyer and seller. amounts, fees, costs, etc, for buyer and seller.
''' '''
if order.status != Order.Status.SUC: if not order.status in [Order.Status.EXP, Order.Status.SUC, Order.Status.PAY, Order.Status.FAI]:
return False, {'bad_summary':'Order has not finished yet'} return False, {'bad_summary':'Order has not finished yet'}
context = {} context = {}

View File

@ -1,4 +1,4 @@
import React, { Component } from "react"; import React, { Component , Suspense } from "react";
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import HomePage from "./HomePage"; import HomePage from "./HomePage";
import { CssBaseline, IconButton , Link} from "@mui/material"; import { CssBaseline, IconButton , Link} from "@mui/material";
@ -36,6 +36,7 @@ export default class App extends Component {
render() { render() {
return ( return (
<Suspense fallback="loading language">
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
<ThemeProvider theme={this.state.dark ? this.darkTheme : this.lightTheme}> <ThemeProvider theme={this.state.dark ? this.darkTheme : this.lightTheme}>
<CssBaseline/> <CssBaseline/>
@ -48,6 +49,7 @@ export default class App extends Component {
<HomePage/> <HomePage/>
</ThemeProvider> </ThemeProvider>
</I18nextProvider> </I18nextProvider>
</Suspense>
); );
} }
} }

View File

@ -294,15 +294,17 @@ bottomBarDesktop =()=>{
} }
LangSelect = () => { LangSelect = () => {
const { i18n} = this.props; const { i18n } = this.props;
const lang = i18n.resolvedLanguage == null ? 'en' : i18n.resolvedLanguage.substring(0,2);
const flagProps = { const flagProps = {
width: 20, width: 20,
height: 20, height: 20,
}; };
return( return(
<Select <Select
size = 'small' size = 'small'
value = {i18n.resolvedLanguage.substring(0,2)} value = {lang}
inputProps={{ inputProps={{
style: {textAlign:"center"} style: {textAlign:"center"}
}} }}

View File

@ -24,6 +24,8 @@ import BoltIcon from '@mui/icons-material/Bolt';
import LinkIcon from '@mui/icons-material/Link'; import LinkIcon from '@mui/icons-material/Link';
import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet'; import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet';
import FavoriteIcon from '@mui/icons-material/Favorite'; import FavoriteIcon from '@mui/icons-material/Favorite';
import RocketLaunchIcon from '@mui/icons-material/RocketLaunch';
import RefreshIcon from '@mui/icons-material/Refresh';
import { NewTabIcon } from "./Icons"; import { NewTabIcon } from "./Icons";
import { getCookie } from "../utils/cookies"; import { getCookie } from "../utils/cookies";
@ -1275,9 +1277,9 @@ handleRatingRobosatsChange=(e)=>{
</Grid> </Grid>
: null} : null}
<Grid container> <Grid item container spacing={3}>
<Grid item xs={show_renew? 6: 12} align="center"> <Grid item xs={show_renew? 6: 12} align="center">
<Button color='primary' onClick={() => {this.props.push('/')}}>{t("Start Again")}</Button> <Button color='primary' variant="outlined" onClick={() => {this.props.push('/')}}><RocketLaunchIcon/>{t("Start Again")}</Button>
</Grid> </Grid>
{show_renew ? {show_renew ?
@ -1285,7 +1287,7 @@ handleRatingRobosatsChange=(e)=>{
{this.state.renewLoading ? {this.state.renewLoading ?
<CircularProgress/> <CircularProgress/>
: :
<Button color='primary' onClick={this.handleRenewOrderButtonPressed}>{t("Renew Order")}</Button> <Button color='primary' variant="outlined" onClick={this.handleRenewOrderButtonPressed}><RefreshIcon/>{t("Renew Order")}</Button>
} }
</Grid> </Grid>
: null} : null}
@ -1299,6 +1301,7 @@ handleRatingRobosatsChange=(e)=>{
makerSummary={this.props.data.maker_summary} makerSummary={this.props.data.maker_summary}
takerSummary={this.props.data.taker_summary} takerSummary={this.props.data.taker_summary}
platformSummary={this.props.data.platform_summary} platformSummary={this.props.data.platform_summary}
orderId={this.props.data.orderId}
/> />
</Grid> </Grid>

View File

@ -6,19 +6,24 @@ import {
ToggleButton, ToggleButton,
ToggleButtonGroup, ToggleButtonGroup,
List, List,
Chip,
ListItem, ListItem,
ListItemText, ListItemText,
ListItemIcon, ListItemIcon,
Grid, Grid,
Divider, Tooltip,
IconButton,
Accordion,
AccordionSummary,
AccordionDetails,
Typography, Typography,
} from "@mui/material" } from "@mui/material"
import { pn } from "../utils/prettyNumbers"; import { pn } from "../utils/prettyNumbers";
import { saveAsJson } from "../utils/saveFile";
// Icons // Icons
import FlagWithProps from "./FlagWithProps"; import FlagWithProps from "./FlagWithProps";
import PercentIcon from '@mui/icons-material/Percent'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import DownloadIcon from '@mui/icons-material/Download';
import AccountBalanceIcon from '@mui/icons-material/AccountBalance'; import AccountBalanceIcon from '@mui/icons-material/AccountBalance';
import RouteIcon from '@mui/icons-material/Route'; import RouteIcon from '@mui/icons-material/Route';
import AccountBoxIcon from '@mui/icons-material/AccountBox'; import AccountBoxIcon from '@mui/icons-material/AccountBox';
@ -39,7 +44,7 @@ type Props = {
makerSummary: Record<string, Item>; makerSummary: Record<string, Item>;
takerSummary: Record<string, Item>; takerSummary: Record<string, Item>;
platformSummary: Record<string, Item>; platformSummary: Record<string, Item>;
bondPercent: number; orderId: number;
} }
const TradeSummary = ({ const TradeSummary = ({
@ -50,145 +55,158 @@ const TradeSummary = ({
makerSummary, makerSummary,
takerSummary, takerSummary,
platformSummary, platformSummary,
bondPercent, orderId,
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const [buttonValue, setButtonValue] = useState<number>(isMaker ? 0 : 2); const [buttonValue, setButtonValue] = useState<number>(isMaker ? 0 : 2);
var userSummary = buttonValue == 0 ? makerSummary : takerSummary; var userSummary = buttonValue == 0 ? makerSummary : takerSummary;
return ( return (
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">
<List> <Accordion defaultExpanded={true} elevation={0} sx={{width:322, position:'relative', right:8}}>
<Divider> <AccordionSummary expandIcon={<ExpandMoreIcon sx={{width:28}} color="primary"/>}>
<Chip label={t("Trade Summary")}/> <Typography sx={{flexGrow:1}} color="text.secondary">{t("Trade Summary")}</Typography>
</Divider> </AccordionSummary>
</List> <AccordionDetails>
<ToggleButtonGroup <div style={{position:'relative',left:14, display:'flex',alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}>
size="small" <ToggleButtonGroup
value={buttonValue} size="small"
exclusive> value={buttonValue}
<ToggleButton value={0} disableRipple={true} onClick={() => setButtonValue(0)}> exclusive>
<Avatar <ToggleButton value={0} disableRipple={true} onClick={() => setButtonValue(0)}>
className="flippedSmallAvatar" <Avatar
sx={{height:24,width:24}} className="flippedSmallAvatar"
alt={makerNick} sx={{height:24,width:24}}
src={window.location.origin +'/static/assets/avatars/' + makerNick + '.png'} alt={makerNick}
/> src={window.location.origin +'/static/assets/avatars/' + makerNick + '.png'}
&nbsp; />
{t("Maker")} &nbsp;
</ToggleButton> {t("Maker")}
<ToggleButton value={1} disableRipple={true} onClick={() => setButtonValue(1)}> </ToggleButton>
<RoboSatsNoTextIcon/> <ToggleButton value={1} disableRipple={true} onClick={() => setButtonValue(1)}>
</ToggleButton> <RoboSatsNoTextIcon/>
<ToggleButton value={2} disableRipple={true} onClick={() => setButtonValue(2)}> </ToggleButton>
{t("Taker")} <ToggleButton value={2} disableRipple={true} onClick={() => setButtonValue(2)}>
&nbsp; {t("Taker")}
<Avatar &nbsp;
className="smallAvatar" <Avatar
sx={{height:24,width:24}} className="smallAvatar"
alt={takerNick} sx={{height:28,width:28}}
src={window.location.origin +'/static/assets/avatars/' + takerNick + '.png'} alt={takerNick}
/> src={window.location.origin +'/static/assets/avatars/' + takerNick + '.png'}
</ToggleButton> />
</ToggleButtonGroup> </ToggleButton>
</ToggleButtonGroup>
{/* Maker/Taker Summary */} <Tooltip enterTouchDelay={250} title={t("Save trade summary as file")}>
<div style={{display: [0,2].includes(buttonValue) ? '':'none'}}> <span>
<List dense={true}> <IconButton
<ListItem> color="primary"
<ListItemIcon> onClick={()=> saveAsJson(`order${orderId}-summary.json`, {'order_id':orderId,'currency':currencyCode,'maker':makerSummary,'taker':takerSummary,'platform':platformSummary})}
<Badge >
overlap="circular" <DownloadIcon sx={{width:26, height:26}}/>
anchorOrigin={{horizontal: 'right', vertical: 'bottom'}} </IconButton>
badgeContent={<div </span>
style={{position:"relative", left:"3px", top:"2px"}}> </Tooltip>
{userSummary.is_buyer ? </div>
<SendReceiveIcon {/* Maker/Taker Summary */}
sx={{transform: "scaleX(-1)",height:"18px",width:"18px"}} <div style={{display: [0,2].includes(buttonValue) ? '':'none'}}>
color="secondary"/> <List dense={true}>
: <SendReceiveIcon <ListItem>
sx={{height:"18px",width:"18px"}} <ListItemIcon>
color="primary"/> <Badge
} overlap="circular"
</div>}> anchorOrigin={{horizontal: 'right', vertical: 'bottom'}}
<AccountBoxIcon sx={{position:'relative',left:-2,width:28,height:28}}/> badgeContent={<div
</Badge> style={{position:"relative", left:"3px", top:"2px"}}>
</ListItemIcon> {userSummary.is_buyer ?
<ListItemText <SendReceiveIcon
primary={userSummary.is_buyer ? t("Buyer") : t("Seller")} sx={{transform: "scaleX(-1)",height:"18px",width:"18px"}}
secondary={t("User role")}/> color="secondary"/>
: <SendReceiveIcon
sx={{height:"18px",width:"18px"}}
color="primary"/>
}
</div>}>
<AccountBoxIcon sx={{position:'relative',left:-2,width:28,height:28}}/>
</Badge>
</ListItemIcon>
<ListItemText
primary={userSummary.is_buyer ? t("Buyer") : t("Seller")}
secondary={t("User role")}/>
<ListItemIcon> <ListItemIcon>
<div style={{position:'relative',left:15,zoom:1.25,opacity: 0.7,msZoom:1.25,WebkitZoom:1.25,MozTransform:'scale(1.25,1.25)',MozTransformOrigin:'left center'}}> <div style={{position:'relative',left:15,zoom:1.25,opacity: 0.7,msZoom:1.25,WebkitZoom:1.25,MozTransform:'scale(1.25,1.25)',MozTransformOrigin:'left center'}}>
<FlagWithProps code={currencyCode}/> <FlagWithProps code={currencyCode}/>
</div> </div>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={(userSummary.is_buyer ? pn(userSummary.sent_fiat) : pn(userSummary.received_fiat))+" "+currencyCode} primary={(userSummary.is_buyer ? pn(userSummary.sent_fiat) : pn(userSummary.received_fiat))+" "+currencyCode}
secondary={userSummary.is_buyer ? t("Sent") : t("Received")}/> secondary={userSummary.is_buyer ? t("Sent") : t("Received")}/>
</ListItem> </ListItem>
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<BitcoinIcon/> <BitcoinIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={pn(userSummary.is_buyer ? userSummary.received_sats : userSummary.sent_sats)+" Sats"} primary={pn(userSummary.is_buyer ? userSummary.received_sats : userSummary.sent_sats)+" Sats"}
secondary={userSummary.is_buyer ? "BTC received" : "BTC sent"}/> secondary={userSummary.is_buyer ? "BTC received" : "BTC sent"}/>
<ListItemText <ListItemText
primary={t("{{tradeFeeSats}} Sats ({{tradeFeePercent}}%)",{tradeFeeSats:userSummary.trade_fee_sats,tradeFeePercent:parseFloat((userSummary.trade_fee_percent*100).toPrecision(3))})} primary={t("{{tradeFeeSats}} Sats ({{tradeFeePercent}}%)",{tradeFeeSats:userSummary.trade_fee_sats,tradeFeePercent:parseFloat((userSummary.trade_fee_percent*100).toPrecision(3))})}
secondary={"Trade fee"}/> secondary={"Trade fee"}/>
</ListItem> </ListItem>
{userSummary.is_swap ? {userSummary.is_swap ?
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<LinkIcon/> <LinkIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("{{swapFeeSats}} Sats ({{swapFeePercent}}%)" , {swapFeeSats:pn(userSummary.swap_fee_sats), swapFeePercent:userSummary.swap_fee_percent})} primary={t("{{swapFeeSats}} Sats ({{swapFeePercent}}%)" , {swapFeeSats:pn(userSummary.swap_fee_sats), swapFeePercent:userSummary.swap_fee_percent})}
secondary={t("Onchain swap fee")}/> secondary={t("Onchain swap fee")}/>
<ListItemText <ListItemText
primary={t("{{miningFeeSats}} Sats",{miningFeeSats:userSummary.mining_fee_sats})} primary={t("{{miningFeeSats}} Sats",{miningFeeSats:userSummary.mining_fee_sats})}
secondary={t("Mining fee")}/> secondary={t("Mining fee")}/>
</ListItem> </ListItem>
: null} : null}
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<LockOpenIcon color="success"/> <LockOpenIcon color="success"/>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("{{bondSats}} Sats ({{bondPercent}}%)" , {bondSats:pn(userSummary.bond_size_sats), bondPercent:userSummary.bond_size_percent})} primary={t("{{bondSats}} Sats ({{bondPercent}}%)" , {bondSats:pn(userSummary.bond_size_sats), bondPercent:userSummary.bond_size_percent})}
secondary={buttonValue === 0 ? t("Maker bond") : t("Taker bond") }/> secondary={buttonValue === 0 ? t("Maker bond") : t("Taker bond") }/>
<ListItemText <ListItemText
sx={{color:'#2e7d32'}} sx={{color:'#2e7d32'}}
primary={<b>{t("Unlocked")}</b>}/> primary={<b>{t("Unlocked")}</b>}/>
</ListItem> </ListItem>
</List> </List>
</div> </div>
{/* Platform Summary */} {/* Platform Summary */}
<div style={{display: buttonValue == 1 ? '':'none'}}> <div style={{display: buttonValue == 1 ? '':'none'}}>
<List dense={true}> <List dense={true}>
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<AccountBalanceIcon/> <AccountBalanceIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("{{revenueSats}} Sats",{revenueSats:platformSummary.trade_revenue_sats})} primary={t("{{revenueSats}} Sats",{revenueSats:platformSummary.trade_revenue_sats})}
secondary={t("Platform trade revenue")}/> secondary={t("Platform trade revenue")}/>
</ListItem> </ListItem>
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<RouteIcon/> <RouteIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("{{routingFeeSats}} MiliSats",{routingFeeSats:platformSummary.routing_fee_sats})} primary={t("{{routingFeeSats}} MiliSats",{routingFeeSats:platformSummary.routing_fee_sats})}
secondary={t("Platform covered routing fee")}/> secondary={t("Platform covered routing fee")}/>
</ListItem> </ListItem>
</List> </List>
</div> </div>
</AccordionDetails>
</Accordion>
</Grid> </Grid>
); );
}; };

View File

@ -3,39 +3,121 @@ import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next"; import { initReactI18next } from "react-i18next";
import HttpApi from 'i18next-http-backend'; import HttpApi from 'i18next-http-backend';
import translationEN from "../locales/en.json"; // import translationEN from "../../static/locales/en.json";
import translationES from "../locales/es.json"; // import translationES from "../../static/locales/es.json";
import translationDE from "../locales/de.json"; // import translationDE from "../../static/locales/de.json";
import translationRU from "../locales/ru.json"; // import translationRU from "../../static/locales/ru.json";
// import translationZH from "../locales/zh.json"; // // import translationZH from "../../static/locales/zh.json";
import translationPL from "../locales/pl.json"; // import translationPL from "../../static/locales/pl.json";
import translationFR from "../locales/fr.json"; // import translationFR from "../../static/locales/fr.json";
import translationCA from "../locales/ca.json"; // import translationCA from "../../static/locales/ca.json";
import translationIT from "../locales/it.json"; // import translationIT from "../../static/locales/it.json";
import translationPT from "../locales/pt.json"; // import translationPT from "../../static/locales/pt.json";
import translationEU from "../locales/eu.json"; // import translationEU from "../../static/locales/eu.json";
import translationSV from "../locales/sv.json"; // import translationSV from "../locales/sv.json";
i18n i18n
.use(HttpApi) .use(HttpApi)
.use(LanguageDetector) .use(LanguageDetector)
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
resources: { // resources: {
en: {translations: translationEN}, // en: {translations: translationEN},
es: {translations: translationES}, // es: {translations: translationES},
ru: {translations: translationRU}, // ru: {translations: translationRU},
de: {translations: translationDE}, // de: {translations: translationDE},
// zh: {translations: translationZH}, // // zh: {translations: translationZH},
pl: {translations: translationPL}, // pl: {translations: translationPL},
fr: {translations: translationFR}, // fr: {translations: translationFR},
ca: {translations: translationCA}, // ca: {translations: translationCA},
it: {translations: translationIT}, // it: {translations: translationIT},
pt: {translations: translationPT}, // pt: {translations: translationPT},
eu: {translations: translationEU}, // eu: {translations: translationEU},
sv: {translations: translationSV}, // sv: {translations: translationSV},
}, // },
backend:{
// path where resources get loaded from, or a function
// returning a path:
// function(lngs, namespaces) { return customPath; }
// the returned path will interpolate lng, ns if provided like giving a static path
// the function might return a promise
// returning falsy will abort the download
//
// If allowMultiLoading is false, lngs and namespaces will have only one element each,
// If allowMultiLoading is true, lngs and namespaces can have multiple elements
loadPath: '/static/locales/{{lng}}.json',
// path to post missing resources, or a function
// function(lng, namespace) { return customPath; }
// the returned path will interpolate lng, ns if provided like giving a static path
addPath: '/static/locales/add/{{lng}}/{{ns}}',
// your backend server supports multiloading
// /locales/resources.json?lng=de+en&ns=ns1+ns2
// Adapter is needed to enable MultiLoading https://github.com/i18next/i18next-multiload-backend-adapter
// Returned JSON structure in this case is
// {
// lang : {
// namespaceA: {},
// namespaceB: {},
// ...etc
// }
// }
allowMultiLoading: false, // set loadPath: '/locales/resources.json?lng={{lng}}&ns={{ns}}' to adapt to multiLoading
// parse data after it has been fetched
// in example use https://www.npmjs.com/package/json5
// here it removes the letter a from the json (bad idea)
//parse: function(data) { return data.replace(/a/g, ''); },
//parse data before it has been sent by addPath
//parsePayload: function(namespace, key, fallbackValue) { return { key } },
// allow cross domain requests
crossDomain: false,
// allow credentials on cross domain requests
withCredentials: false,
// overrideMimeType sets request.overrideMimeType("application/json")
overrideMimeType: false,
// custom request headers sets request.setRequestHeader(key, value)
// customHeaders: {
// authorization: 'foo',
// // ...
// },
// can also be a function, that returns the headers
// customHeaders: () => ({
// authorization: 'foo',
// // ...
// }),
// requestOptions: { // used for fetch, can also be a function (payload) => ({ method: 'GET' })
// mode: 'cors',
// credentials: 'same-origin',
// cache: 'default'
// },
// define a custom request function
// can be used to support XDomainRequest in IE 8 and 9
//
// 'options' will be this entire options object
// 'url' will be passed the value of 'loadPath'
// 'payload' will be a key:value object used when saving missing translations
// 'callback' is a function that takes two parameters, 'err' and 'res'.
// 'err' should be an error
// 'res' should be an object with a 'status' property and a 'data' property containing a stringified object instance beeing the key:value translation pairs for the
// requested language and namespace, or null in case of an error.
//request: function (options, url, payload, callback) {},
// adds parameters to resource URL. 'example.com' -> 'example.com?v=1.3.5'
// queryStringParams: { v: '1.3.5' },
reloadInterval: false // can be used to reload resources in a specific interval (useful in server environments)
},
fallbackLng: "en", fallbackLng: "en",
debug: false, debug: false,